for a moment, everything works

This commit is contained in:
2025-02-21 23:53:31 +01:00
parent 9e7648bc72
commit cfa8b6ee52
23 changed files with 491 additions and 371 deletions

View File

@@ -42,6 +42,13 @@ pub trait AtomicVariant {}
pub trait Atomic: 'static + Sized {
type Variant: AtomicVariant;
type Data: Clone + Coding + Sized + 'static;
/// Register handlers for IPC calls. If this atom implements [Supports], you
/// should register your implementations here. If this atom doesn't
/// participate in IPC at all, use the below body.
/// ```
/// MethodSetBuilder::new()
/// ```
// this method isn't default-implemented to prevent bugs from forgetting to register IPC requests.
fn reg_reqs() -> MethodSetBuilder<Self>;
}
impl<A: Atomic> AtomCard for A {
@@ -106,9 +113,9 @@ impl ForeignAtom<'static> {
ForeignAtom { _life: PhantomData, atom, ctx: handle.ctx.clone(), expr: Some(handle), pos }
}
pub async fn request<M: AtomMethod>(&self, m: M) -> Option<M::Response> {
let rep = (self.ctx.reqnot.request(api::Fwd(
let rep = (self.ctx.reqnot().request(api::Fwd(
self.atom.clone(),
Sym::parse(M::NAME, &self.ctx.i).await.unwrap().tok().to_api(),
Sym::parse(M::NAME, self.ctx.i()).await.unwrap().tok().to_api(),
enc_vec(&m).await,
)))
.await?;
@@ -125,7 +132,7 @@ impl fmt::Debug for ForeignAtom<'_> {
}
impl Format for ForeignAtom<'_> {
async fn print<'a>(&'a self, _c: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit {
FmtUnit::from_api(&self.ctx.reqnot.request(api::ExtAtomPrint(self.atom.clone())).await)
FmtUnit::from_api(&self.ctx.reqnot().request(api::ExtAtomPrint(self.atom.clone())).await)
}
}
impl AtomRepr for ForeignAtom<'_> {
@@ -145,7 +152,7 @@ pub struct NotTypAtom {
impl NotTypAtom {
pub async fn mk_err(&self) -> OrcErr {
mk_err(
self.ctx.i.i("Not the expected type").await,
self.ctx.i().i("Not the expected type").await,
format!("This expression is not a {}", self.typ.name()),
[self.pos.clone().into()],
)
@@ -192,7 +199,7 @@ impl<A: AtomCard> MethodSetBuilder<A> {
handlers: stream::from_iter(self.handlers.iter())
.then(|(k, v)| {
clone!(ctx; async move {
(Sym::parse(k, &ctx.i).await.unwrap(), v.clone())
(Sym::parse(k, ctx.i()).await.unwrap(), v.clone())
})
})
.collect()
@@ -257,9 +264,9 @@ impl<A: AtomicFeatures> TypAtom<'_, A> {
pub async fn request<M: AtomMethod>(&self, req: M) -> M::Response
where A: Supports<M> {
M::Response::decode(Pin::new(
&mut &(self.data.ctx.reqnot.request(api::Fwd(
&mut &(self.data.ctx.reqnot().request(api::Fwd(
self.data.atom.clone(),
Sym::parse(M::NAME, &self.data.ctx.i).await.unwrap().tok().to_api(),
Sym::parse(M::NAME, self.data.ctx.i()).await.unwrap().tok().to_api(),
enc_vec(&req).await,
)))
.await
@@ -275,7 +282,7 @@ impl<A: AtomicFeatures> Deref for TypAtom<'_, A> {
pub struct AtomCtx<'a>(pub &'a [u8], pub Option<api::AtomId>, pub SysCtx);
impl FmtCtx for AtomCtx<'_> {
fn i(&self) -> &Interner { &self.2.i }
fn i(&self) -> &Interner { self.2.i() }
}
pub trait AtomDynfo: 'static {

View File

@@ -28,20 +28,23 @@ use crate::atom::{
};
use crate::expr::{Expr, ExprHandle};
use crate::gen_expr::{GExpr, bot};
use crate::system::SysCtx;
use crate::system::{SysCtx, SysCtxEntry};
use crate::system_ctor::CtedObj;
pub struct OwnedVariant;
impl AtomicVariant for OwnedVariant {}
impl<A: OwnedAtom + Atomic<Variant = OwnedVariant>> AtomicFeaturesImpl<OwnedVariant> for A {
fn _factory(self) -> AtomFactory {
AtomFactory::new(move |ctx| async move {
let serial = ctx.obj_store.0.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
let serial =
ctx.get_or_default::<ObjStore>().next_id.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
let atom_id = api::AtomId(NonZero::new(serial + 1).unwrap());
let (typ_id, _) = get_info::<A>(ctx.cted.inst().card());
let (typ_id, _) = get_info::<A>(ctx.get::<CtedObj>().inst().card());
let mut data = enc_vec(&typ_id).await;
self.encode(Pin::<&mut Vec<u8>>::new(&mut data)).await;
ctx.obj_store.1.read().await.insert(atom_id, Box::new(self));
api::Atom { drop: Some(atom_id), data, owner: ctx.id }
ctx.get_or_default::<ObjStore>().objects.read().await.insert(atom_id, Box::new(self));
eprintln!("Created atom {:?} of type {}", atom_id, type_name::<A>());
api::Atom { drop: Some(atom_id), data, owner: ctx.sys_id() }
})
}
fn _info() -> Self::_Info { OwnedAtomDynfo { msbuild: A::reg_reqs(), ms: OnceCell::new() } }
@@ -55,8 +58,9 @@ pub(crate) struct AtomReadGuard<'a> {
}
impl<'a> AtomReadGuard<'a> {
async fn new(id: api::AtomId, ctx: &'a SysCtx) -> Self {
let guard = ctx.obj_store.1.read().await;
assert!(guard.get(&id).is_some(), "Received invalid atom ID: {}", id.0);
let guard = ctx.get_or_default::<ObjStore>().objects.read().await;
let valid = guard.iter().map(|i| i.0).collect_vec();
assert!(guard.get(&id).is_some(), "Received invalid atom ID: {:?} not in {:?}", id, valid);
Self { id, guard }
}
}
@@ -66,7 +70,7 @@ impl Deref for AtomReadGuard<'_> {
}
pub(crate) async fn take_atom(id: api::AtomId, ctx: &SysCtx) -> Box<dyn DynOwnedAtom> {
let mut g = ctx.obj_store.1.write().await;
let mut g = ctx.get_or_default::<ObjStore>().objects.write().await;
g.remove(&id).unwrap_or_else(|| panic!("Received invalid atom ID: {}", id.0))
}
@@ -219,7 +223,7 @@ pub trait OwnedAtom: Atomic<Variant = OwnedVariant> + Any + Clone + 'static {
fn val(&self) -> impl Future<Output = Cow<'_, Self::Data>>;
#[allow(unused_variables)]
fn call_ref(&self, arg: ExprHandle) -> impl Future<Output = GExpr> {
async move { bot([err_not_callable(&arg.ctx.i).await]) }
async move { bot([err_not_callable(arg.ctx.i()).await]) }
}
fn call(self, arg: ExprHandle) -> impl Future<Output = GExpr> {
async {
@@ -231,7 +235,7 @@ pub trait OwnedAtom: Atomic<Variant = OwnedVariant> + Any + Clone + 'static {
}
#[allow(unused_variables)]
fn command(self, ctx: SysCtx) -> impl Future<Output = OrcRes<Option<GExpr>>> {
async move { Err(err_not_command(&ctx.i).await.into()) }
async move { Err(err_not_command(ctx.i()).await.into()) }
}
#[allow(unused_variables)]
fn free(self, ctx: SysCtx) -> impl Future<Output = ()> { async {} }
@@ -313,4 +317,9 @@ impl<T: OwnedAtom> DynOwnedAtom for T {
}
}
pub type ObjStore = Rc<(AtomicU64, RwLock<MemoMap<api::AtomId, Box<dyn DynOwnedAtom>>>)>;
#[derive(Default)]
struct ObjStore {
next_id: AtomicU64,
objects: RwLock<MemoMap<api::AtomId, Box<dyn DynOwnedAtom>>>,
}
impl SysCtxEntry for ObjStore {}

View File

@@ -19,16 +19,17 @@ use crate::atom::{
use crate::expr::ExprHandle;
use crate::gen_expr::{GExpr, bot};
use crate::system::SysCtx;
use crate::system_ctor::CtedObj;
pub struct ThinVariant;
impl AtomicVariant for ThinVariant {}
impl<A: ThinAtom + Atomic<Variant = ThinVariant>> AtomicFeaturesImpl<ThinVariant> for A {
fn _factory(self) -> AtomFactory {
AtomFactory::new(move |ctx| async move {
let (id, _) = get_info::<A>(ctx.cted.inst().card());
let (id, _) = get_info::<A>(ctx.get::<CtedObj>().inst().card());
let mut buf = enc_vec(&id).await;
self.encode(Pin::new(&mut buf)).await;
api::Atom { drop: None, data: buf, owner: ctx.id }
api::Atom { drop: None, data: buf, owner: ctx.sys_id() }
})
}
fn _info() -> Self::_Info { ThinAtomDynfo { msbuild: Self::reg_reqs(), ms: OnceCell::new() } }
@@ -106,7 +107,7 @@ impl<T: ThinAtom> AtomDynfo for ThinAtomDynfo<T> {
fn drop<'a>(&'a self, AtomCtx(buf, _, ctx): AtomCtx<'a>) -> LocalBoxFuture<'a, ()> {
async move {
let string_self = T::decode(Pin::new(&mut &buf[..])).await.print(ctx.clone()).await;
writeln!(ctx.logger, "Received drop signal for non-drop atom {string_self:?}");
writeln!(ctx.logger(), "Received drop signal for non-drop atom {string_self:?}");
}
.boxed_local()
}
@@ -117,11 +118,11 @@ pub trait ThinAtom:
{
#[allow(unused_variables)]
fn call(&self, arg: ExprHandle) -> impl Future<Output = GExpr> {
async move { bot([err_not_callable(&arg.ctx.i).await]) }
async move { bot([err_not_callable(arg.ctx.i()).await]) }
}
#[allow(unused_variables)]
fn command(&self, ctx: SysCtx) -> impl Future<Output = OrcRes<Option<GExpr>>> {
async move { Err(err_not_command(&ctx.i).await.into()) }
async move { Err(err_not_command(ctx.i()).await.into()) }
}
#[allow(unused_variables)]
fn print(&self, ctx: SysCtx) -> impl Future<Output = FmtUnit> {

View File

@@ -34,10 +34,10 @@ async fn err_type(pos: Pos, i: &Interner) -> OrcErr {
impl<A: AtomicFeatures> TryFromExpr for TypAtom<'_, A> {
async fn try_from_expr(expr: Expr) -> OrcRes<Self> {
match expr.atom().await {
Err(ex) => Err(err_not_atom(ex.data().await.pos.clone(), &ex.ctx().i).await.into()),
Err(ex) => Err(err_not_atom(ex.data().await.pos.clone(), ex.ctx().i()).await.into()),
Ok(f) => match downcast_atom::<A>(f).await {
Ok(a) => Ok(a),
Err(f) => Err(err_type(f.pos(), &f.ctx().i).await.into()),
Err(f) => Err(err_type(f.pos(), f.ctx().i()).await.into()),
},
}
}

View File

@@ -15,7 +15,7 @@ use futures::future::{LocalBoxFuture, join_all};
use futures::{FutureExt, StreamExt};
use hashbrown::HashMap;
use itertools::Itertools;
use orchid_api::ApplyMacro;
use orchid_api::{ApplyMacro, ExtMsgSet};
use orchid_api_traits::{Decode, Encode, enc_vec};
use orchid_base::builtin::{ExtPort, Spawner};
use orchid_base::char_filter::{char_filter_match, char_filter_union, mk_char_filter};
@@ -32,14 +32,14 @@ use trait_set::trait_set;
use crate::api;
use crate::atom::{AtomCtx, AtomDynfo, AtomTypeId};
use crate::atom_owned::{ObjStore, take_atom};
use crate::atom_owned::take_atom;
use crate::fs::VirtFS;
use crate::lexer::{LexContext, err_cascade, err_not_applicable};
use crate::macros::{Rule, RuleCtx};
use crate::msg::{recv_parent_msg, send_parent_msg};
use crate::system::{SysCtx, atom_by_idx};
use crate::system_ctor::{CtedObj, DynSystemCtor};
use crate::tree::{GenTok, GenTokTree, LazyMemberFactory, TIACtxImpl, do_extra};
use crate::tree::{GenTok, GenTokTree, LazyMemberFactory, TreeIntoApiCtxImpl, do_extra};
pub type ExtReq<'a> = RequestHandle<'a, api::ExtMsgSet>;
pub type ExtReqNot = ReqNot<api::ExtMsgSet>;
@@ -61,11 +61,11 @@ pub enum MemberRecord {
}
pub struct SystemRecord {
cted: CtedObj,
vfses: HashMap<api::VfsId, &'static dyn VirtFS>,
declfs: api::EagerVfs,
lazy_members: HashMap<api::TreeId, MemberRecord>,
rules: HashMap<api::MacroId, Rc<Rule>>,
ctx: SysCtx,
}
trait_set! {
@@ -78,14 +78,13 @@ trait_set! {
}
pub async fn with_atom_record<'a, F: Future<Output = SysCtx>, T>(
get_sys_ctx: &impl Fn(api::SysId, ReqNot<api::ExtMsgSet>) -> F,
reqnot: ReqNot<api::ExtMsgSet>,
get_sys_ctx: &impl Fn(api::SysId) -> F,
atom: &'a api::Atom,
cb: impl WARCallback<'a, T>,
) -> T {
let mut data = &atom.data[..];
let ctx = get_sys_ctx(atom.owner, reqnot).await;
let inst = ctx.cted.inst();
let ctx = get_sys_ctx(atom.owner).await;
let inst = ctx.get::<CtedObj>().inst();
let id = AtomTypeId::decode(Pin::new(&mut data)).await;
let atom_record = atom_by_idx(inst.card(), id.clone()).expect("Atom ID reserved");
cb(atom_record, ctx, id, data).await
@@ -108,6 +107,7 @@ pub struct ExtensionOwner {
rn: ReqNot<api::ExtMsgSet>,
out_recv: Receiver<Vec<u8>>,
out_send: Sender<Vec<u8>>,
ext_header: api::ExtensionHeader,
}
impl ExtPort for ExtensionOwner {
@@ -125,6 +125,12 @@ impl ExtPort for ExtensionOwner {
.boxed_local()
}
}
impl ExtensionOwner {
pub fn ext_header(&self) -> &api::ExtensionHeader { &self.ext_header }
// pub async fn new(data: ExtensionData, spawner: Spawner, header:
// api::HostHeader) -> Self { let decls =
// }
}
pub async fn extension_main_logic(data: ExtensionData, spawner: Spawner) {
let api::HostHeader { log_strategy, msg_logs } =
@@ -134,7 +140,7 @@ pub async fn extension_main_logic(data: ExtensionData, spawner: Spawner) {
.map(|(id, sys)| (u16::try_from(id).expect("more than u16max system ctors"), sys))
.map(|(id, sys)| sys.decl(api::SysDeclId(NonZero::new(id + 1).unwrap())))
.collect_vec();
let systems = Rc::new(Mutex::new(HashMap::<api::SysId, SystemRecord>::new()));
let systems_lock = Rc::new(Mutex::new(HashMap::<api::SysId, SystemRecord>::new()));
api::ExtensionHeader { name: data.name.to_string(), systems: decls.clone() }
.encode(Pin::new(&mut buf))
.await;
@@ -143,41 +149,48 @@ pub async fn extension_main_logic(data: ExtensionData, spawner: Spawner) {
let exiting = Arc::new(AtomicBool::new(false));
let logger = Logger::new(log_strategy);
let msg_logger = Logger::new(msg_logs);
let interner_cell = Rc::new(RefCell::new(None::<Rc<Interner>>));
let interner_cell = Rc::new(RefCell::new(None::<Interner>));
let interner_weak = Rc::downgrade(&interner_cell);
let obj_store = ObjStore::default();
let mk_ctx = clone!(
logger, systems, spawner, obj_store, interner_weak;
move |id: api::SysId, reqnot: ReqNot<api::ExtMsgSet>| {
clone!(logger, systems, spawner, obj_store, interner_weak; async move {
let cted = systems.lock().await[&id].cted.clone();
let interner_cell = (interner_weak.upgrade())
.expect("mk_ctx called after Interner rc dropped");
let i = (interner_cell.borrow().clone())
.expect("mk_ctx called before interner initialized");
SysCtx { id, cted, logger, reqnot, spawner, obj_store, i: i.clone() }
}.boxed_local())
});
let systems_weak = Rc::downgrade(&systems_lock);
let get_ctx = clone!(systems_weak; move |id: api::SysId| clone!(systems_weak; async move {
let systems =
systems_weak.upgrade().expect("System table dropped before request processing done");
let x = systems.lock().await.get(&id).expect("System not found").ctx.clone();
x
}));
let init_ctx = {
clone!(systems_weak, interner_weak, spawner, logger);
move |id: api::SysId, cted: CtedObj, reqnot: ReqNot<ExtMsgSet>| {
clone!(systems_weak, interner_weak, spawner, logger; async move {
let interner_rc =
interner_weak.upgrade().expect("System construction order while shutting down");
let i = interner_rc.borrow().clone().expect("mk_ctx called very early, no interner!");
SysCtx::new(id, i, reqnot, spawner, logger, cted)
})
}
};
let rn = ReqNot::<api::ExtMsgSet>::new(
msg_logger.clone(),
move |a, _| async move { send_parent_msg(a).await.unwrap() }.boxed_local(),
clone!(systems, exiting, mk_ctx; move |n, reqnot| {
clone!(systems, exiting, mk_ctx; async move {
clone!(systems_weak, exiting, get_ctx; move |n, reqnot| {
clone!(systems_weak, exiting, get_ctx; async move {
match n {
api::HostExtNotif::Exit => exiting.store(true, Ordering::Relaxed),
api::HostExtNotif::SystemDrop(api::SystemDrop(sys_id)) =>
mem::drop(systems.lock().await.remove(&sys_id)),
if let Some(rc) = systems_weak.upgrade() {
mem::drop(rc.lock().await.remove(&sys_id))
},
api::HostExtNotif::AtomDrop(api::AtomDrop(sys_id, atom)) => {
let ctx = mk_ctx(sys_id, reqnot).await;
let ctx = get_ctx(sys_id).await;
take_atom(atom, &ctx).await.dyn_free(ctx.clone()).await
}
}
}.boxed_local())
}),
{
clone!(systems, logger, mk_ctx, interner_weak, obj_store, spawner, decls, msg_logger);
clone!(logger, get_ctx, init_ctx, systems_weak, interner_weak, spawner, decls, msg_logger);
move |hand, req| {
clone!(systems, logger, mk_ctx, interner_weak, obj_store, spawner, decls, msg_logger);
clone!(logger, get_ctx, init_ctx, systems_weak, interner_weak, spawner, decls, msg_logger);
async move {
let interner_cell = interner_weak.upgrade().expect("Interner dropped before request");
let i = interner_cell.borrow().clone().expect("Request arrived before interner set");
@@ -197,21 +210,13 @@ pub async fn extension_main_logic(data: ExtensionData, spawner: Spawner) {
});
let lazy_mems = Mutex::new(HashMap::new());
let rules = Mutex::new(HashMap::new());
let ctx = SysCtx {
cted: cted.clone(),
id: new_sys.id,
logger: logger.clone(),
reqnot: hand.reqnot(),
i: i.clone(),
obj_store: obj_store.clone(),
spawner: spawner.clone(),
};
let ctx = init_ctx(new_sys.id, cted.clone(), hand.reqnot()).await;
let const_root = stream::from_iter(cted.inst().dyn_env())
.then(|(k, v)| {
let (req, lazy_mems, rules) = (&hand, &lazy_mems, &rules);
clone!(i, ctx; async move {
let name = i.i(&k).await.to_api();
let value = v.into_api(&mut TIACtxImpl {
let value = v.into_api(&mut TreeIntoApiCtxImpl {
lazy_members: &mut *lazy_mems.lock().await,
rules: &mut *rules.lock().await,
sys: ctx,
@@ -229,17 +234,19 @@ pub async fn extension_main_logic(data: ExtensionData, spawner: Spawner) {
let record = SystemRecord {
declfs,
vfses,
cted,
ctx,
lazy_members: lazy_mems.into_inner(),
rules: rules.into_inner(),
};
let systems = systems_weak.upgrade().expect("System constructed during shutdown");
systems.lock().await.insert(new_sys.id, record);
hand
.handle(&new_sys, &api::SystemInst { lex_filter, const_root, line_types: vec![] })
.await
},
api::HostExtReq::GetMember(get_tree @ api::GetMember(sys_id, tree_id)) => {
let sys_ctx = mk_ctx(sys_id, hand.reqnot()).await;
let sys_ctx = get_ctx(sys_id).await;
let systems = systems_weak.upgrade().expect("Member queried during shutdown");
let mut systems_g = systems.lock().await;
let SystemRecord { lazy_members, rules, .. } =
systems_g.get_mut(&sys_id).expect("System not found");
@@ -248,8 +255,8 @@ pub async fn extension_main_logic(data: ExtensionData, spawner: Spawner) {
Some(MemberRecord::Res) => panic!("This tree has already been transmitted"),
Some(MemberRecord::Gen(path, cb)) => (path, cb),
};
let tree = cb.build(Sym::new(path.clone(), &i).await.unwrap()).await;
let mut tia_ctx = TIACtxImpl {
let tree = cb.build(Sym::new(path.clone(), &i).await.unwrap(), sys_ctx.clone()).await;
let mut tia_ctx = TreeIntoApiCtxImpl {
sys: sys_ctx,
path: Substack::Bottom,
basepath: &path,
@@ -260,32 +267,33 @@ pub async fn extension_main_logic(data: ExtensionData, spawner: Spawner) {
hand.handle(&get_tree, &tree.into_api(&mut tia_ctx).await).await
},
api::HostExtReq::VfsReq(api::VfsReq::GetVfs(get_vfs @ api::GetVfs(sys_id))) => {
let systems = systems_weak.upgrade().expect("VFS root requested during shutdown");
let systems_g = systems.lock().await;
hand.handle(&get_vfs, &systems_g[&sys_id].declfs).await
},
api::HostExtReq::SysReq(api::SysReq::SysFwded(fwd)) => {
let api::SysFwded(sys_id, payload) = fwd;
let ctx = mk_ctx(sys_id, hand.reqnot()).await;
let sys = ctx.cted.inst();
let ctx = get_ctx(sys_id).await;
let sys = ctx.cted().inst();
sys.dyn_request(hand, payload).await
},
api::HostExtReq::VfsReq(api::VfsReq::VfsRead(vfs_read)) => {
let api::VfsRead(sys_id, vfs_id, path) = &vfs_read;
let ctx = mk_ctx(*sys_id, hand.reqnot()).await;
let ctx = get_ctx(*sys_id).await;
let systems = systems_weak.upgrade().expect("VFS requested during shutdoown");
let systems_g = systems.lock().await;
let path = join_all(path.iter().map(|t| Tok::from_api(*t, &i))).await;
let vfs = systems_g[sys_id].vfses[vfs_id].load(&path, ctx).await;
hand.handle(&vfs_read, &vfs).await
},
api::HostExtReq::LexExpr(lex @ api::LexExpr { sys, text, pos, id }) => {
let systems_g = systems.lock().await;
let lexers = systems_g[&sys].cted.inst().dyn_lexers();
mem::drop(systems_g);
let sys_ctx = get_ctx(sys).await;
let text = Tok::from_api(text, &i).await;
let ctx = LexContext { sys, id, pos, reqnot: hand.reqnot(), text: &text, i: &i };
let trigger_char = text.chars().nth(pos as usize).unwrap();
let err_na = err_not_applicable(&i).await;
let err_cascade = err_cascade(&i).await;
let lexers = sys_ctx.cted().inst().dyn_lexers();
for lx in lexers.iter().filter(|l| char_filter_match(l.char_filter(), trigger_char)) {
match lx.lex(&text[pos as usize..], &ctx).await {
Err(e) if e.any(|e| *e == err_na) => continue,
@@ -294,10 +302,9 @@ pub async fn extension_main_logic(data: ExtensionData, spawner: Spawner) {
return hand.handle(&lex, &eopt).await;
},
Ok((s, expr)) => {
let ctx = mk_ctx(sys, hand.reqnot()).await;
let expr = expr
.to_api(&mut |f, r| {
clone!(ctx; async move { do_extra(f, r, ctx).await }).boxed_local()
clone!(sys_ctx; async move { do_extra(f, r, sys_ctx).await }).boxed_local()
})
.await;
let pos = (text.len() - s.len()) as u32;
@@ -310,8 +317,8 @@ pub async fn extension_main_logic(data: ExtensionData, spawner: Spawner) {
},
api::HostExtReq::ParseLine(pline) => {
let api::ParseLine { exported, comments, sys, line } = &pline;
let mut ctx = mk_ctx(*sys, hand.reqnot()).await;
let parsers = ctx.cted.inst().dyn_parsers();
let mut ctx = get_ctx(*sys).await;
let parsers = ctx.cted().inst().dyn_parsers();
let comments = join_all(comments.iter().map(|c| Comment::from_api(c, &i))).await;
let line: Vec<GenTokTree> = ttv_from_api(line, &mut ctx, &i).await;
let snip = Snippet::new(line.first().expect("Empty line"), &line, &i);
@@ -337,7 +344,7 @@ pub async fn extension_main_logic(data: ExtensionData, spawner: Spawner) {
api::HostExtReq::AtomReq(atom_req) => {
let atom = atom_req.get_atom();
let atom_req = atom_req.clone();
with_atom_record(&mk_ctx, hand.reqnot(), atom, move |nfo, ctx, id, buf| {
with_atom_record(&get_ctx, atom, move |nfo, ctx, id, buf| {
async move {
let actx = AtomCtx(buf, atom.drop, ctx.clone());
match &atom_req {
@@ -389,16 +396,16 @@ pub async fn extension_main_logic(data: ExtensionData, spawner: Spawner) {
api::HostExtReq::DeserAtom(deser) => {
let api::DeserAtom(sys, buf, refs) = &deser;
let mut read = &mut &buf[..];
let ctx = mk_ctx(*sys, hand.reqnot()).await;
let ctx = get_ctx(*sys).await;
let id = AtomTypeId::decode(Pin::new(&mut read)).await;
let inst = ctx.cted.inst();
let inst = ctx.cted().inst();
let nfo = atom_by_idx(inst.card(), id).expect("Deserializing atom with invalid ID");
hand.handle(&deser, &nfo.deserialize(ctx.clone(), read, refs).await).await
},
orchid_api::HostExtReq::ApplyMacro(am) => {
let tok = hand.will_handle_as(&am);
let ApplyMacro { id, params, run_id, sys } = am;
let sys_ctx = mk_ctx(sys, hand.reqnot()).await;
let sys_ctx = get_ctx(sys).await;
let mut ctx =
RuleCtx { args: ahash::HashMap::default(), run_id, sys: sys_ctx.clone() };
for (k, v) in params {
@@ -408,6 +415,7 @@ pub async fn extension_main_logic(data: ExtensionData, spawner: Spawner) {
);
}
let err_cascade = err_cascade(&i).await;
let systems = systems_weak.upgrade().expect("macro call during shutdown");
let systems_g = systems.lock().await;
let rule = &systems_g[&sys].rules[&id];
match (rule.apply)(ctx).await {
@@ -432,7 +440,7 @@ pub async fn extension_main_logic(data: ExtensionData, spawner: Spawner) {
}
},
);
*interner_cell.borrow_mut() = Some(Rc::new(Interner::new_replica(rn.clone().map())));
*interner_cell.borrow_mut() = Some(Interner::new_replica(rn.clone().map()));
while !exiting.load(Ordering::Relaxed) {
let rcvd = recv_parent_msg().await.unwrap();
spawner(Box::pin(clone!(rn; async move { rn.receive(&rcvd).await })))

View File

@@ -23,7 +23,7 @@ impl ExprHandle {
pub(crate) fn from_args(ctx: SysCtx, tk: api::ExprTicket) -> Self { Self { ctx, tk } }
pub fn get_ctx(&self) -> SysCtx { self.ctx.clone() }
pub async fn clone(&self) -> Self {
self.ctx.reqnot.notify(api::Acquire(self.ctx.id, self.tk)).await;
self.ctx.reqnot().notify(api::Acquire(self.ctx.sys_id(), self.tk)).await;
Self { ctx: self.ctx.clone(), tk: self.tk }
}
}
@@ -34,9 +34,9 @@ impl fmt::Debug for ExprHandle {
}
impl Drop for ExprHandle {
fn drop(&mut self) {
let notif = api::Release(self.ctx.id, self.tk);
let SysCtx { reqnot, spawner, .. } = self.ctx.clone();
spawner(Box::pin(async move { reqnot.notify(notif).await }))
let notif = api::Release(self.ctx.sys_id(), self.tk);
let reqnot = self.ctx.reqnot().clone();
self.ctx.spawner()(Box::pin(async move { reqnot.notify(notif).await }))
}
}
@@ -53,13 +53,13 @@ impl Expr {
pub async fn data(&self) -> &ExprData {
(self.data.get_or_init(async {
let details = self.handle.ctx.reqnot.request(api::Inspect { target: self.handle.tk }).await;
let pos = Pos::from_api(&details.location, &self.handle.ctx.i).await;
let details = self.handle.ctx.reqnot().request(api::Inspect { target: self.handle.tk }).await;
let pos = Pos::from_api(&details.location, self.handle.ctx.i()).await;
let kind = match details.kind {
api::InspectedKind::Atom(a) =>
ExprKind::Atom(ForeignAtom::new(self.handle.clone(), a, pos.clone())),
api::InspectedKind::Bottom(b) =>
ExprKind::Bottom(OrcErrv::from_api(&b, &self.handle.ctx.i).await),
ExprKind::Bottom(OrcErrv::from_api(&b, self.handle.ctx.i()).await),
api::InspectedKind::Opaque => ExprKind::Opaque,
};
ExprData { pos, kind }
@@ -83,7 +83,7 @@ impl Format for Expr {
ExprKind::Opaque => "OPAQUE".to_string().into(),
ExprKind::Bottom(b) => format!("Bottom({b})").into(),
ExprKind::Atom(a) =>
FmtUnit::from_api(&self.handle.ctx.reqnot.request(ExtAtomPrint(a.atom.clone())).await),
FmtUnit::from_api(&self.handle.ctx.reqnot().request(ExtAtomPrint(a.atom.clone())).await),
}
}
}

View File

@@ -13,7 +13,6 @@ use never::Never;
use orchid_api_traits::Encode;
use orchid_base::clone;
use orchid_base::error::OrcRes;
use orchid_base::format::{FmtCtxImpl, Format, take_first};
use orchid_base::name::Sym;
use trait_set::trait_set;
@@ -22,7 +21,7 @@ use crate::atom_owned::{DeserializeCtx, OwnedAtom, OwnedVariant};
use crate::conv::ToExpr;
use crate::expr::{Expr, ExprHandle};
use crate::gen_expr::GExpr;
use crate::system::SysCtx;
use crate::system::{SysCtx, SysCtxEntry};
trait_set! {
trait FunCB = Fn(Vec<Expr>) -> LocalBoxFuture<'static, OrcRes<GExpr>> + 'static;
@@ -33,9 +32,9 @@ pub trait ExprFunc<I, O>: Clone + 'static {
fn apply(&self, v: Vec<Expr>) -> impl Future<Output = OrcRes<GExpr>>;
}
thread_local! {
static FUNS: Rc<Mutex<HashMap<Sym, (u8, Rc<dyn FunCB>)>>> = Rc::default();
}
#[derive(Default)]
struct FunsCtx(Mutex<HashMap<Sym, (u8, Rc<dyn FunCB>)>>);
impl SysCtxEntry for FunsCtx {}
/// An Atom representing a partially applied named native function. These
/// partial calls are serialized into the name of the native function and the
@@ -50,9 +49,9 @@ pub(crate) struct Fun {
fun: Rc<dyn FunCB>,
}
impl Fun {
pub async fn new<I, O, F: ExprFunc<I, O>>(path: Sym, f: F) -> Self {
let funs = FUNS.with(|funs| funs.clone());
let mut fung = funs.lock().await;
pub async fn new<I, O, F: ExprFunc<I, O>>(path: Sym, ctx: SysCtx, f: F) -> Self {
let funs: &FunsCtx = ctx.get_or_default();
let mut fung = funs.0.lock().await;
let fun = if let Some(x) = fung.get(&path) {
x.1.clone()
} else {
@@ -89,8 +88,8 @@ impl OwnedAtom for Fun {
}
async fn deserialize(mut ctx: impl DeserializeCtx, args: Self::Refs) -> Self {
let sys = ctx.sys();
let path = Sym::from_api(ctx.decode().await, &sys.i).await;
let (arity, fun) = FUNS.with(|f| f.clone()).lock().await.get(&path).unwrap().clone();
let path = Sym::from_api(ctx.decode().await, sys.i()).await;
let (arity, fun) = sys.get_or_default::<FunsCtx>().0.lock().await.get(&path).unwrap().clone();
Self { args, arity, path, fun }
}
async fn print(&self, _: SysCtx) -> orchid_base::format::FmtUnit {

View File

@@ -4,10 +4,11 @@ use ahash::HashMap;
use futures::future::{LocalBoxFuture, join_all};
use itertools::Itertools;
use never::Never;
use orchid_api::ExtMsgSet;
use orchid_base::error::OrcRes;
use orchid_base::interner::Tok;
use orchid_base::macros::{MTree, mtreev_from_api, mtreev_to_api};
use orchid_base::reqnot::Requester;
use orchid_base::reqnot::{ReqNot, Requester};
use trait_set::trait_set;
use crate::api;
@@ -44,11 +45,11 @@ impl<'a> RuleCtx<'a> {
run_id: self.run_id,
query: mtreev_to_api(tree, &mut |b| match *b {}).await,
};
let Some(treev) = self.sys.reqnot.request(req).await else {
return Err(err_cascade(&self.sys.i).await.into());
let Some(treev) = self.sys.get::<ReqNot<ExtMsgSet>>().request(req).await else {
return Err(err_cascade(self.sys.i()).await.into());
};
static ATOM_MSG: &str = "Returned atom from Rule recursion";
Ok(mtreev_from_api(&treev, &self.sys.i, &mut |_| panic!("{ATOM_MSG}")).await)
Ok(mtreev_from_api(&treev, self.sys.i(), &mut |_| panic!("{ATOM_MSG}")).await)
}
pub fn getv(&mut self, key: &Tok<String>) -> Vec<MTree<'a, Never>> {
self.args.remove(key).expect("Key not found")
@@ -78,7 +79,7 @@ impl Rule {
pub(crate) async fn into_api(self, ctx: &mut impl TreeIntoApiCtx) -> api::MacroRule {
api::MacroRule {
comments: join_all(self.comments.iter().map(|c| async {
api::Comment { text: ctx.sys().i.i(c).await.to_api(), location: api::Location::Inherit }
api::Comment { text: ctx.sys().i().i(c).await.to_api(), location: api::Location::Inherit }
}))
.await,
location: api::Location::Inherit,

View File

@@ -1,5 +1,5 @@
use core::fmt;
use std::any::{TypeId, type_name};
use std::any::{Any, TypeId, type_name};
use std::fmt;
use std::future::Future;
use std::num::NonZero;
use std::pin::Pin;
@@ -7,6 +7,8 @@ use std::rc::Rc;
use futures::future::LocalBoxFuture;
use hashbrown::HashMap;
use memo_map::MemoMap;
use orchid_api::ExtMsgSet;
use orchid_api_traits::{Coding, Decode};
use orchid_base::boxed_iter::BoxedIter;
use orchid_base::builtin::Spawner;
@@ -16,7 +18,6 @@ use orchid_base::reqnot::{Receipt, ReqNot};
use crate::api;
use crate::atom::{AtomCtx, AtomDynfo, AtomTypeId, AtomicFeatures, ForeignAtom, TypAtom, get_info};
use crate::atom_owned::ObjStore;
use crate::entrypoint::ExtReq;
use crate::fs::DeclFs;
use crate::func_atom::Fun;
@@ -116,11 +117,11 @@ where A: AtomicFeatures {
let mut data = &foreign.atom.data[..];
let ctx = foreign.ctx.clone();
let value = AtomTypeId::decode(Pin::new(&mut data)).await;
let own_inst = ctx.cted.inst();
let owner = if ctx.id == foreign.atom.owner {
let own_inst = ctx.get::<CtedObj>().inst();
let owner = if *ctx.get::<api::SysId>() == foreign.atom.owner {
own_inst.card()
} else {
(ctx.cted.deps().find(|s| s.id() == foreign.atom.owner))
(ctx.get::<CtedObj>().deps().find(|s| s.id() == foreign.atom.owner))
.ok_or_else(|| foreign.clone())?
.get_card()
};
@@ -133,18 +134,80 @@ where A: AtomicFeatures {
Ok(TypAtom { value, data: foreign })
}
// #[derive(Clone)]
// pub struct SysCtx {
// pub reqnot: ReqNot<api::ExtMsgSet>,
// pub spawner: Spawner,
// pub id: api::SysId,
// pub cted: CtedObj,
// pub logger: Logger,
// pub obj_store: ObjStore,
// pub i: Rc<Interner>,
// }
// impl fmt::Debug for SysCtx {
// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
// write!(f, "SysCtx({:?})", self.id)
// }
// }
#[derive(Clone)]
pub struct SysCtx {
pub reqnot: ReqNot<api::ExtMsgSet>,
pub spawner: Spawner,
pub id: api::SysId,
pub cted: CtedObj,
pub logger: Logger,
pub obj_store: ObjStore,
pub i: Rc<Interner>,
pub struct SysCtx(Rc<MemoMap<TypeId, Box<dyn Any>>>);
impl SysCtx {
pub fn new(
id: api::SysId,
i: Interner,
reqnot: ReqNot<ExtMsgSet>,
spawner: Spawner,
logger: Logger,
cted: CtedObj,
) -> Self {
let this = Self(Rc::new(MemoMap::new()));
this.add(id).add(i).add(reqnot).add(spawner).add(logger).add(cted);
this
}
pub fn add<T: SysCtxEntry>(&self, t: T) -> &Self {
assert!(self.0.insert(TypeId::of::<T>(), Box::new(t)), "Key already exists");
self
}
pub fn get_or_insert<T: SysCtxEntry>(&self, f: impl FnOnce() -> T) -> &T {
(self.0.get_or_insert_owned(TypeId::of::<T>(), || Box::new(f())).downcast_ref())
.expect("Keyed by TypeId")
}
pub fn get_or_default<T: SysCtxEntry + Default>(&self) -> &T {
self.get_or_insert(|| {
let rc_id = self.0.as_ref() as *const _ as *const () as usize;
eprintln!("Default-initializing {} in {}", type_name::<T>(), rc_id);
T::default()
})
}
pub fn try_get<T: SysCtxEntry>(&self) -> Option<&T> {
Some(self.0.get(&TypeId::of::<T>())?.downcast_ref().expect("Keyed by TypeId"))
}
pub fn get<T: SysCtxEntry>(&self) -> &T {
self.try_get().unwrap_or_else(|| panic!("Context {} missing", type_name::<T>()))
}
/// Shorthand to get the [Interner] instance
pub fn i(&self) -> &Interner { self.get::<Interner>() }
/// Shorthand to get the messaging link
pub fn reqnot(&self) -> &ReqNot<ExtMsgSet> { self.get::<ReqNot<ExtMsgSet>>() }
/// Shorthand to get the system ID
pub fn sys_id(&self) -> api::SysId { *self.get::<api::SysId>() }
/// Shorthand to get the task spawner callback
pub fn spawner(&self) -> &Spawner { self.get::<Spawner>() }
/// Shorthand to get the logger
pub fn logger(&self) -> &Logger { self.get::<Logger>() }
/// Shorthand to get the constructed system object
pub fn cted(&self) -> &CtedObj { self.get::<CtedObj>() }
}
impl fmt::Debug for SysCtx {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "SysCtx({:?})", self.id)
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "SysCtx({:?})", self.sys_id())
}
}
pub trait SysCtxEntry: 'static + Sized {}
impl SysCtxEntry for api::SysId {}
impl SysCtxEntry for ReqNot<api::ExtMsgSet> {}
impl SysCtxEntry for Spawner {}
impl SysCtxEntry for CtedObj {}
impl SysCtxEntry for Logger {}
impl SysCtxEntry for Interner {}

View File

@@ -46,7 +46,7 @@ pub struct GenItem {
impl GenItem {
pub async fn into_api(self, ctx: &mut impl TreeIntoApiCtx) -> api::Item {
let kind = match self.kind {
GenItemKind::Export(n) => api::ItemKind::Export(ctx.sys().i.i::<String>(&n).await.to_api()),
GenItemKind::Export(n) => api::ItemKind::Export(ctx.sys().i().i::<String>(&n).await.to_api()),
GenItemKind::Member(mem) => api::ItemKind::Member(mem.into_api(ctx).await),
GenItemKind::Import(cn) => api::ItemKind::Import(cn.tok().to_api()),
GenItemKind::Macro(priority, gen_rules) => {
@@ -60,7 +60,7 @@ impl GenItem {
let comments = join_all(self.comments.iter().map(|c| async {
api::Comment {
location: api::Location::Inherit,
text: ctx.sys().i.i::<String>(c).await.to_api(),
text: ctx.sys().i().i::<String>(c).await.to_api(),
}
}))
.await;
@@ -92,8 +92,8 @@ pub fn root_mod(
(name.to_string(), kind)
}
pub fn fun<I, O>(exported: bool, name: &str, xf: impl ExprFunc<I, O>) -> Vec<GenItem> {
let fac = LazyMemberFactory::new(move |sym| async {
return MemKind::Const(build_lambdas(Fun::new(sym, xf).await, 0));
let fac = LazyMemberFactory::new(move |sym, ctx| async {
return MemKind::Const(build_lambdas(Fun::new(sym, ctx, xf).await, 0));
fn build_lambdas(fun: Fun, i: u64) -> GExpr {
if i < fun.arity().into() {
return lambda(i, [build_lambdas(fun, i + 1)]);
@@ -129,16 +129,16 @@ pub fn comments<'a>(
trait_set! {
trait LazyMemberCallback =
FnOnce(Sym) -> LocalBoxFuture<'static, MemKind> + DynClone
FnOnce(Sym, SysCtx) -> LocalBoxFuture<'static, MemKind> + DynClone
}
pub struct LazyMemberFactory(Box<dyn LazyMemberCallback>);
impl LazyMemberFactory {
pub fn new<F: Future<Output = MemKind> + 'static>(
cb: impl FnOnce(Sym) -> F + Clone + 'static,
cb: impl FnOnce(Sym, SysCtx) -> F + Clone + 'static,
) -> Self {
Self(Box::new(|s| cb(s).boxed_local()))
Self(Box::new(|s, ctx| cb(s, ctx).boxed_local()))
}
pub async fn build(self, path: Sym) -> MemKind { (self.0)(path).await }
pub async fn build(self, path: Sym, ctx: SysCtx) -> MemKind { (self.0)(path, ctx).await }
}
impl Clone for LazyMemberFactory {
fn clone(&self) -> Self { Self(clone_box(&*self.0)) }
@@ -157,7 +157,7 @@ pub struct GenMember {
}
impl GenMember {
pub async fn into_api(self, ctx: &mut impl TreeIntoApiCtx) -> api::Member {
let name = ctx.sys().i.i::<String>(&self.name).await;
let name = ctx.sys().i().i::<String>(&self.name).await;
api::Member {
kind: self.kind.into_api(&mut ctx.push_path(name.clone())).await,
name: name.to_api(),
@@ -197,7 +197,7 @@ pub trait TreeIntoApiCtx {
fn req(&self) -> &impl ReqHandlish;
}
pub struct TIACtxImpl<'a, 'b, RH: ReqHandlish> {
pub struct TreeIntoApiCtxImpl<'a, 'b, RH: ReqHandlish> {
pub sys: SysCtx,
pub basepath: &'a [Tok<String>],
pub path: Substack<'a, Tok<String>>,
@@ -206,10 +206,10 @@ pub struct TIACtxImpl<'a, 'b, RH: ReqHandlish> {
pub req: &'a RH,
}
impl<RH: ReqHandlish> TreeIntoApiCtx for TIACtxImpl<'_, '_, RH> {
impl<RH: ReqHandlish> TreeIntoApiCtx for TreeIntoApiCtxImpl<'_, '_, RH> {
fn sys(&self) -> SysCtx { self.sys.clone() }
fn push_path(&mut self, seg: Tok<String>) -> impl TreeIntoApiCtx {
TIACtxImpl {
TreeIntoApiCtxImpl {
req: self.req,
lazy_members: self.lazy_members,
rules: self.rules,