forked from Orchid/orchid
All sorts of test scaffolding works now
This commit is contained in:
@@ -16,6 +16,7 @@ hashbrown = "0.15.2"
|
||||
itertools = "0.14.0"
|
||||
konst = "0.3.16"
|
||||
lazy_static = "1.5.0"
|
||||
memo-map = "0.3.3"
|
||||
never = "0.1.0"
|
||||
once_cell = "1.20.2"
|
||||
orchid-api = { version = "0.1.0", path = "../orchid-api" }
|
||||
|
||||
@@ -2,6 +2,7 @@ use std::any::{Any, TypeId, type_name};
|
||||
use std::fmt;
|
||||
use std::future::Future;
|
||||
use std::marker::PhantomData;
|
||||
use std::num::NonZeroU32;
|
||||
use std::ops::Deref;
|
||||
use std::pin::Pin;
|
||||
use std::rc::Rc;
|
||||
@@ -12,6 +13,7 @@ use async_std::stream;
|
||||
use dyn_clone::{DynClone, clone_box};
|
||||
use futures::future::LocalBoxFuture;
|
||||
use futures::{FutureExt, StreamExt};
|
||||
use orchid_api_derive::Coding;
|
||||
use orchid_api_traits::{Coding, Decode, Encode, Request, enc_vec};
|
||||
use orchid_base::clone;
|
||||
use orchid_base::error::{OrcErr, OrcRes, mk_err};
|
||||
@@ -29,6 +31,9 @@ use crate::expr::{Expr, ExprData, ExprHandle, ExprKind};
|
||||
use crate::gen_expr::GExpr;
|
||||
use crate::system::{DynSystemCard, SysCtx, atom_info_for, downcast_atom};
|
||||
|
||||
#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Coding)]
|
||||
pub struct AtomTypeId(pub NonZeroU32);
|
||||
|
||||
pub trait AtomCard: 'static + Sized {
|
||||
type Data: Clone + Coding + Sized;
|
||||
}
|
||||
@@ -72,7 +77,7 @@ impl<A: Atomic + AtomicFeaturesImpl<A::Variant>> AtomicFeatures for A {
|
||||
|
||||
pub fn get_info<A: AtomCard>(
|
||||
sys: &(impl DynSystemCard + ?Sized),
|
||||
) -> (api::AtomId, Box<dyn AtomDynfo>) {
|
||||
) -> (AtomTypeId, Box<dyn AtomDynfo>) {
|
||||
atom_info_for(sys, TypeId::of::<A>()).unwrap_or_else(|| {
|
||||
panic!("Atom {} not associated with system {}", type_name::<A>(), sys.name())
|
||||
})
|
||||
|
||||
@@ -1,20 +1,24 @@
|
||||
use std::any::{Any, TypeId, type_name};
|
||||
use std::borrow::Cow;
|
||||
use std::future::Future;
|
||||
use std::num::NonZero;
|
||||
use std::ops::Deref;
|
||||
use std::pin::Pin;
|
||||
use std::rc::Rc;
|
||||
use std::sync::atomic::AtomicU64;
|
||||
|
||||
use async_once_cell::OnceCell;
|
||||
use async_std::io::{Read, Write};
|
||||
use async_std::sync::{RwLock, RwLockReadGuard};
|
||||
use futures::FutureExt;
|
||||
use futures::future::{LocalBoxFuture, ready};
|
||||
use itertools::Itertools;
|
||||
use memo_map::MemoMap;
|
||||
use never::Never;
|
||||
use orchid_api::AtomId;
|
||||
use orchid_api_traits::{Decode, Encode, enc_vec};
|
||||
use orchid_base::clone;
|
||||
use orchid_base::error::OrcRes;
|
||||
use orchid_base::format::FmtUnit;
|
||||
use orchid_base::id_store::{IdRecord, IdStore};
|
||||
use orchid_base::name::Sym;
|
||||
|
||||
use crate::api;
|
||||
@@ -31,23 +35,39 @@ 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 rec = ctx.obj_store.add(Box::new(self));
|
||||
let (id, _) = get_info::<A>(ctx.cted.inst().card());
|
||||
let mut data = enc_vec(&id).await;
|
||||
rec.encode(Pin::<&mut Vec<u8>>::new(&mut data)).await;
|
||||
api::Atom { drop: Some(api::AtomId(rec.id())), data, owner: ctx.id }
|
||||
let serial = ctx.obj_store.0.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 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 }
|
||||
})
|
||||
}
|
||||
fn _info() -> Self::_Info { OwnedAtomDynfo { msbuild: A::reg_reqs(), ms: OnceCell::new() } }
|
||||
type _Info = OwnedAtomDynfo<A>;
|
||||
}
|
||||
|
||||
fn with_atom<'a, U>(
|
||||
/// While an atom read guard is held, no atom can be removed.
|
||||
pub(crate) struct AtomReadGuard<'a> {
|
||||
id: api::AtomId,
|
||||
ctx: &'a SysCtx,
|
||||
f: impl FnOnce(IdRecord<'a, Box<dyn DynOwnedAtom>>) -> U,
|
||||
) -> U {
|
||||
f(ctx.obj_store.get(id.0).unwrap_or_else(|| panic!("Received invalid atom ID: {}", id.0)))
|
||||
guard: RwLockReadGuard<'a, MemoMap<AtomId, Box<dyn DynOwnedAtom>>>,
|
||||
}
|
||||
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);
|
||||
Self { id, guard }
|
||||
}
|
||||
}
|
||||
impl Deref for AtomReadGuard<'_> {
|
||||
type Target = dyn DynOwnedAtom;
|
||||
fn deref(&self) -> &Self::Target { &**self.guard.get(&self.id).unwrap() }
|
||||
}
|
||||
|
||||
pub(crate) async fn take_atom(id: api::AtomId, ctx: &SysCtx) -> Box<dyn DynOwnedAtom> {
|
||||
let mut g = ctx.obj_store.1.write().await;
|
||||
g.remove(&id).unwrap_or_else(|| panic!("Received invalid atom ID: {}", id.0))
|
||||
}
|
||||
|
||||
pub struct OwnedAtomDynfo<T: OwnedAtom> {
|
||||
@@ -64,24 +84,19 @@ impl<T: OwnedAtom> AtomDynfo for OwnedAtomDynfo<T> {
|
||||
.boxed_local()
|
||||
}
|
||||
fn call(&self, AtomCtx(_, id, ctx): AtomCtx, arg: api::ExprTicket) -> LocalBoxFuture<'_, GExpr> {
|
||||
with_atom(id.unwrap(), &ctx, |a| a.remove()).dyn_call(ctx.clone(), arg)
|
||||
async move { take_atom(id.unwrap(), &ctx).await.dyn_call(ctx.clone(), arg).await }.boxed_local()
|
||||
}
|
||||
fn call_ref<'a>(
|
||||
&'a self,
|
||||
AtomCtx(_, id, ctx): AtomCtx<'a>,
|
||||
arg: api::ExprTicket,
|
||||
) -> LocalBoxFuture<'a, GExpr> {
|
||||
async move {
|
||||
with_atom(id.unwrap(), &ctx, |a| clone!(ctx; async move { a.dyn_call_ref(ctx, arg).await }))
|
||||
.await
|
||||
}
|
||||
.boxed_local()
|
||||
async move { AtomReadGuard::new(id.unwrap(), &ctx).await.dyn_call_ref(ctx.clone(), arg).await }
|
||||
.boxed_local()
|
||||
}
|
||||
fn print(&self, AtomCtx(_, id, ctx): AtomCtx<'_>) -> LocalBoxFuture<'_, FmtUnit> {
|
||||
async move {
|
||||
with_atom(id.unwrap(), &ctx, |a| clone!(ctx; async move { a.dyn_print(ctx).await })).await
|
||||
}
|
||||
.boxed_local()
|
||||
async move { AtomReadGuard::new(id.unwrap(), &ctx).await.dyn_print(ctx.clone()).await }
|
||||
.boxed_local()
|
||||
}
|
||||
fn handle_req<'a, 'b: 'a, 'c: 'a>(
|
||||
&'a self,
|
||||
@@ -91,13 +106,9 @@ impl<T: OwnedAtom> AtomDynfo for OwnedAtomDynfo<T> {
|
||||
rep: Pin<&'c mut dyn Write>,
|
||||
) -> LocalBoxFuture<'a, bool> {
|
||||
async move {
|
||||
with_atom(id.unwrap(), &ctx, |a| {
|
||||
clone!(ctx; async move {
|
||||
let ms = self.ms.get_or_init(self.msbuild.pack(ctx.clone())).await;
|
||||
ms.dispatch(a.as_any_ref().downcast_ref().unwrap(), ctx, key, req, rep).await
|
||||
})
|
||||
})
|
||||
.await
|
||||
let a = AtomReadGuard::new(id.unwrap(), &ctx).await;
|
||||
let ms = self.ms.get_or_init(self.msbuild.pack(ctx.clone())).await;
|
||||
ms.dispatch(a.as_any_ref().downcast_ref().unwrap(), ctx.clone(), key, req, rep).await
|
||||
}
|
||||
.boxed_local()
|
||||
}
|
||||
@@ -105,12 +116,10 @@ impl<T: OwnedAtom> AtomDynfo for OwnedAtomDynfo<T> {
|
||||
&'a self,
|
||||
AtomCtx(_, id, ctx): AtomCtx<'a>,
|
||||
) -> LocalBoxFuture<'a, OrcRes<Option<GExpr>>> {
|
||||
async move { with_atom(id.unwrap(), &ctx, |a| a.remove().dyn_command(ctx.clone())).await }
|
||||
.boxed_local()
|
||||
async move { take_atom(id.unwrap(), &ctx).await.dyn_command(ctx.clone()).await }.boxed_local()
|
||||
}
|
||||
fn drop(&self, AtomCtx(_, id, ctx): AtomCtx) -> LocalBoxFuture<'_, ()> {
|
||||
async move { with_atom(id.unwrap(), &ctx, |a| a.remove().dyn_free(ctx.clone())).await }
|
||||
.boxed_local()
|
||||
async move { take_atom(id.unwrap(), &ctx).await.dyn_free(ctx.clone()).await }.boxed_local()
|
||||
}
|
||||
fn serialize<'a, 'b: 'a>(
|
||||
&'a self,
|
||||
@@ -120,9 +129,8 @@ impl<T: OwnedAtom> AtomDynfo for OwnedAtomDynfo<T> {
|
||||
async move {
|
||||
let id = id.unwrap();
|
||||
id.encode(write.as_mut()).await;
|
||||
with_atom(id, &ctx, |a| clone!(ctx; async move { a.dyn_serialize(ctx, write).await }))
|
||||
.await
|
||||
.map(|v| v.into_iter().map(|t| t.handle().tk).collect_vec())
|
||||
let refs = AtomReadGuard::new(id, &ctx).await.dyn_serialize(ctx.clone(), write).await;
|
||||
refs.map(|v| v.into_iter().map(|t| t.handle().tk).collect_vec())
|
||||
}
|
||||
.boxed_local()
|
||||
}
|
||||
@@ -305,4 +313,4 @@ impl<T: OwnedAtom> DynOwnedAtom for T {
|
||||
}
|
||||
}
|
||||
|
||||
pub type ObjStore = Rc<IdStore<Box<dyn DynOwnedAtom>>>;
|
||||
pub type ObjStore = Rc<(AtomicU64, RwLock<MemoMap<api::AtomId, Box<dyn DynOwnedAtom>>>)>;
|
||||
|
||||
@@ -35,7 +35,7 @@ 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()),
|
||||
Ok(f) => match downcast_atom(f).await {
|
||||
Ok(f) => match downcast_atom::<A>(f).await {
|
||||
Ok(a) => Ok(a),
|
||||
Err(f) => Err(err_type(f.pos(), &f.ctx().i).await.into()),
|
||||
},
|
||||
|
||||
@@ -23,7 +23,7 @@ use orchid_base::clone;
|
||||
use orchid_base::interner::{Interner, Tok};
|
||||
use orchid_base::logging::Logger;
|
||||
use orchid_base::macros::{mtreev_from_api, mtreev_to_api};
|
||||
use orchid_base::name::{PathSlice, Sym};
|
||||
use orchid_base::name::Sym;
|
||||
use orchid_base::parse::{Comment, Snippet};
|
||||
use orchid_base::reqnot::{ReqNot, RequestHandle, Requester};
|
||||
use orchid_base::tree::{ttv_from_api, ttv_to_api};
|
||||
@@ -31,8 +31,8 @@ use substack::Substack;
|
||||
use trait_set::trait_set;
|
||||
|
||||
use crate::api;
|
||||
use crate::atom::{AtomCtx, AtomDynfo};
|
||||
use crate::atom_owned::ObjStore;
|
||||
use crate::atom::{AtomCtx, AtomDynfo, AtomTypeId};
|
||||
use crate::atom_owned::{ObjStore, take_atom};
|
||||
use crate::fs::VirtFS;
|
||||
use crate::lexer::{LexContext, err_cascade, err_not_applicable};
|
||||
use crate::macros::{Rule, RuleCtx};
|
||||
@@ -72,7 +72,7 @@ trait_set! {
|
||||
pub trait WARCallback<'a, T> = FnOnce(
|
||||
Box<dyn AtomDynfo>,
|
||||
SysCtx,
|
||||
api::AtomId,
|
||||
AtomTypeId,
|
||||
&'a [u8]
|
||||
) -> LocalBoxFuture<'a, T>
|
||||
}
|
||||
@@ -86,8 +86,8 @@ pub async fn with_atom_record<'a, F: Future<Output = SysCtx>, T>(
|
||||
let mut data = &atom.data[..];
|
||||
let ctx = get_sys_ctx(atom.owner, reqnot).await;
|
||||
let inst = ctx.cted.inst();
|
||||
let id = api::AtomId::decode(Pin::new(&mut data)).await;
|
||||
let atom_record = atom_by_idx(inst.card(), id).expect("Atom ID reserved");
|
||||
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
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ impl ExtPort for ExtensionOwner {
|
||||
}
|
||||
|
||||
pub async fn extension_main_logic(data: ExtensionData, spawner: Spawner) {
|
||||
let api::HostHeader { log_strategy } =
|
||||
let api::HostHeader { log_strategy, msg_logs } =
|
||||
api::HostHeader::decode(Pin::new(&mut async_std::io::stdin())).await;
|
||||
let mut buf = Vec::new();
|
||||
let decls = (data.systems.iter().enumerate())
|
||||
@@ -142,6 +142,7 @@ pub async fn extension_main_logic(data: ExtensionData, spawner: Spawner) {
|
||||
std::io::stdout().flush().unwrap();
|
||||
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_weak = Rc::downgrade(&interner_cell);
|
||||
let obj_store = ObjStore::default();
|
||||
@@ -158,26 +159,29 @@ pub async fn extension_main_logic(data: ExtensionData, spawner: Spawner) {
|
||||
}.boxed_local())
|
||||
});
|
||||
let rn = ReqNot::<api::ExtMsgSet>::new(
|
||||
logger.clone(),
|
||||
msg_logger.clone(),
|
||||
move |a, _| async move { send_parent_msg(a).await.unwrap() }.boxed_local(),
|
||||
clone!(systems, exiting, mk_ctx, obj_store; move |n, reqnot| {
|
||||
clone!(systems, exiting, mk_ctx, obj_store; async move {
|
||||
clone!(systems, exiting, mk_ctx; move |n, reqnot| {
|
||||
clone!(systems, exiting, mk_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)),
|
||||
api::HostExtNotif::AtomDrop(api::AtomDrop(sys_id, atom)) =>
|
||||
obj_store.get(atom.0).unwrap().remove().dyn_free(mk_ctx(sys_id, reqnot).await).await,
|
||||
api::HostExtNotif::AtomDrop(api::AtomDrop(sys_id, atom)) => {
|
||||
let ctx = mk_ctx(sys_id, reqnot).await;
|
||||
take_atom(atom, &ctx).await.dyn_free(ctx.clone()).await
|
||||
}
|
||||
}
|
||||
}.boxed_local())
|
||||
}),
|
||||
{
|
||||
clone!(systems, logger, mk_ctx, interner_weak, obj_store, spawner, decls);
|
||||
clone!(systems, logger, mk_ctx, interner_weak, obj_store, spawner, decls, msg_logger);
|
||||
move |hand, req| {
|
||||
clone!(systems, logger, mk_ctx, interner_weak, obj_store, spawner, decls);
|
||||
clone!(systems, logger, mk_ctx, interner_weak, obj_store, 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");
|
||||
writeln!(msg_logger, "{} extension received request {req:?}", data.name);
|
||||
match req {
|
||||
api::HostExtReq::Ping(ping @ api::Ping) => hand.handle(&ping, &()).await,
|
||||
api::HostExtReq::Sweep(sweep @ api::Sweep) =>
|
||||
@@ -270,7 +274,7 @@ pub async fn extension_main_logic(data: ExtensionData, spawner: Spawner) {
|
||||
let ctx = mk_ctx(*sys_id, hand.reqnot()).await;
|
||||
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(PathSlice::new(&path), ctx).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 }) => {
|
||||
@@ -386,7 +390,7 @@ pub async fn extension_main_logic(data: ExtensionData, spawner: Spawner) {
|
||||
let api::DeserAtom(sys, buf, refs) = &deser;
|
||||
let mut read = &mut &buf[..];
|
||||
let ctx = mk_ctx(*sys, hand.reqnot()).await;
|
||||
let id = api::AtomId::decode(Pin::new(&mut read)).await;
|
||||
let id = AtomTypeId::decode(Pin::new(&mut read)).await;
|
||||
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
|
||||
|
||||
@@ -3,7 +3,9 @@ use std::rc::Rc;
|
||||
|
||||
use async_once_cell::OnceCell;
|
||||
use derive_destructure::destructure;
|
||||
use orchid_api::ExtAtomPrint;
|
||||
use orchid_base::error::OrcErrv;
|
||||
use orchid_base::format::{FmtCtx, FmtUnit, Format};
|
||||
use orchid_base::location::Pos;
|
||||
use orchid_base::reqnot::Requester;
|
||||
|
||||
@@ -75,6 +77,16 @@ impl Expr {
|
||||
|
||||
pub fn gen(&self) -> GExpr { GExpr { pos: Pos::SlotTarget, kind: GExprKind::Slot(self.clone()) } }
|
||||
}
|
||||
impl Format for Expr {
|
||||
async fn print<'a>(&'a self, _c: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit {
|
||||
match &self.data().await.kind {
|
||||
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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ExprData {
|
||||
|
||||
@@ -3,8 +3,7 @@ use std::num::NonZero;
|
||||
use futures::FutureExt;
|
||||
use futures::future::LocalBoxFuture;
|
||||
use hashbrown::HashMap;
|
||||
use orchid_base::interner::Interner;
|
||||
use orchid_base::name::PathSlice;
|
||||
use orchid_base::interner::{Interner, Tok};
|
||||
|
||||
use crate::api;
|
||||
use crate::system::SysCtx;
|
||||
@@ -12,7 +11,7 @@ use crate::system::SysCtx;
|
||||
pub trait VirtFS: Send + Sync + 'static {
|
||||
fn load<'a>(
|
||||
&'a self,
|
||||
path: &'a PathSlice,
|
||||
path: &'a [Tok<String>],
|
||||
ctx: SysCtx,
|
||||
) -> LocalBoxFuture<'a, api::OrcResult<api::Loaded>>;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ 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;
|
||||
|
||||
@@ -61,6 +62,7 @@ impl Fun {
|
||||
};
|
||||
Self { args: vec![], arity: F::ARITY, path, fun }
|
||||
}
|
||||
pub fn arity(&self) -> u8 { self.arity }
|
||||
}
|
||||
impl Atomic for Fun {
|
||||
type Data = ();
|
||||
@@ -71,6 +73,7 @@ impl OwnedAtom for Fun {
|
||||
type Refs = Vec<Expr>;
|
||||
async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) }
|
||||
async fn call_ref(&self, arg: ExprHandle) -> GExpr {
|
||||
std::io::Write::flush(&mut std::io::stderr()).unwrap();
|
||||
let new_args = self.args.iter().cloned().chain([Expr::from_handle(Rc::new(arg))]).collect_vec();
|
||||
if new_args.len() == self.arity.into() {
|
||||
(self.fun)(new_args).await.to_expr()
|
||||
@@ -90,6 +93,9 @@ impl OwnedAtom for Fun {
|
||||
let (arity, fun) = FUNS.with(|f| f.clone()).lock().await.get(&path).unwrap().clone();
|
||||
Self { args, arity, path, fun }
|
||||
}
|
||||
async fn print(&self, _: SysCtx) -> orchid_base::format::FmtUnit {
|
||||
format!("{}:{}/{}", self.path, self.args.len(), self.arity).into()
|
||||
}
|
||||
}
|
||||
|
||||
/// An Atom representing a partially applied native lambda. These are not
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use core::fmt;
|
||||
use std::any::TypeId;
|
||||
use std::any::{TypeId, type_name};
|
||||
use std::future::Future;
|
||||
use std::num::NonZero;
|
||||
use std::pin::Pin;
|
||||
@@ -15,7 +15,7 @@ use orchid_base::logging::Logger;
|
||||
use orchid_base::reqnot::{Receipt, ReqNot};
|
||||
|
||||
use crate::api;
|
||||
use crate::atom::{AtomCtx, AtomDynfo, AtomicFeatures, ForeignAtom, TypAtom, get_info};
|
||||
use crate::atom::{AtomCtx, AtomDynfo, AtomTypeId, AtomicFeatures, ForeignAtom, TypAtom, get_info};
|
||||
use crate::atom_owned::ObjStore;
|
||||
use crate::entrypoint::ExtReq;
|
||||
use crate::fs::DeclFs;
|
||||
@@ -49,21 +49,21 @@ fn general_atoms() -> impl Iterator<Item = Option<Box<dyn AtomDynfo>>> {
|
||||
pub fn atom_info_for(
|
||||
sys: &(impl DynSystemCard + ?Sized),
|
||||
tid: TypeId,
|
||||
) -> Option<(api::AtomId, Box<dyn AtomDynfo>)> {
|
||||
(sys.atoms().enumerate().map(|(i, o)| (NonZero::new(i as u64 + 1).unwrap(), o)))
|
||||
.chain(general_atoms().enumerate().map(|(i, o)| (NonZero::new(!(i as u64)).unwrap(), o)))
|
||||
.filter_map(|(i, o)| o.map(|a| (api::AtomId(i), a)))
|
||||
) -> Option<(AtomTypeId, Box<dyn AtomDynfo>)> {
|
||||
(sys.atoms().enumerate().map(|(i, o)| (NonZero::new(i as u32 + 1).unwrap(), o)))
|
||||
.chain(general_atoms().enumerate().map(|(i, o)| (NonZero::new(!(i as u32)).unwrap(), o)))
|
||||
.filter_map(|(i, o)| o.map(|a| (AtomTypeId(i), a)))
|
||||
.find(|ent| ent.1.tid() == tid)
|
||||
}
|
||||
|
||||
pub fn atom_by_idx(
|
||||
sys: &(impl DynSystemCard + ?Sized),
|
||||
tid: api::AtomId,
|
||||
tid: AtomTypeId,
|
||||
) -> Option<Box<dyn AtomDynfo>> {
|
||||
if (u64::from(tid.0) >> (u64::BITS - 1)) & 1 == 1 {
|
||||
general_atoms().nth(!u64::from(tid.0) as usize).unwrap()
|
||||
if (u32::from(tid.0) >> (u32::BITS - 1)) & 1 == 1 {
|
||||
general_atoms().nth(!u32::from(tid.0) as usize).unwrap()
|
||||
} else {
|
||||
sys.atoms().nth(u64::from(tid.0) as usize - 1).unwrap()
|
||||
sys.atoms().nth(u32::from(tid.0) as usize - 1).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ pub async fn resolv_atom(
|
||||
sys: &(impl DynSystemCard + ?Sized),
|
||||
atom: &api::Atom,
|
||||
) -> Box<dyn AtomDynfo> {
|
||||
let tid = api::AtomId::decode(Pin::new(&mut &atom.data[..8])).await;
|
||||
let tid = AtomTypeId::decode(Pin::new(&mut &atom.data[..])).await;
|
||||
atom_by_idx(sys, tid).expect("Value of nonexistent type found")
|
||||
}
|
||||
|
||||
@@ -115,18 +115,22 @@ pub async fn downcast_atom<A>(foreign: ForeignAtom<'_>) -> Result<TypAtom<'_, A>
|
||||
where A: AtomicFeatures {
|
||||
let mut data = &foreign.atom.data[..];
|
||||
let ctx = foreign.ctx.clone();
|
||||
let value = api::AtomId::decode(Pin::new(&mut data)).await;
|
||||
let info_ent = (ctx.cted.deps().find(|s| s.id() == foreign.atom.owner))
|
||||
.map(|sys| get_info::<A>(sys.get_card()))
|
||||
.filter(|(pos, _)| value == *pos);
|
||||
match info_ent {
|
||||
None => Err(foreign),
|
||||
Some((_, info)) => {
|
||||
let val = info.decode(AtomCtx(data, foreign.atom.drop, ctx)).await;
|
||||
let value = *val.downcast::<A::Data>().expect("atom decode returned wrong type");
|
||||
Ok(TypAtom { value, data: foreign })
|
||||
},
|
||||
let value = AtomTypeId::decode(Pin::new(&mut data)).await;
|
||||
let own_inst = ctx.cted.inst();
|
||||
let owner = if ctx.id == foreign.atom.owner {
|
||||
own_inst.card()
|
||||
} else {
|
||||
(ctx.cted.deps().find(|s| s.id() == foreign.atom.owner))
|
||||
.ok_or_else(|| foreign.clone())?
|
||||
.get_card()
|
||||
};
|
||||
let (typ_id, dynfo) = get_info::<A>(owner);
|
||||
if value != typ_id {
|
||||
return Err(foreign);
|
||||
}
|
||||
let val = dynfo.decode(AtomCtx(data, foreign.atom.drop, ctx)).await;
|
||||
let value = *val.downcast::<A::Data>().expect("atom decode returned wrong type");
|
||||
Ok(TypAtom { value, data: foreign })
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
||||
@@ -21,7 +21,7 @@ use crate::atom::{AtomFactory, ForeignAtom};
|
||||
use crate::conv::ToExpr;
|
||||
use crate::entrypoint::MemberRecord;
|
||||
use crate::func_atom::{ExprFunc, Fun};
|
||||
use crate::gen_expr::GExpr;
|
||||
use crate::gen_expr::{GExpr, arg, call, lambda, seq};
|
||||
use crate::macros::Rule;
|
||||
use crate::system::SysCtx;
|
||||
|
||||
@@ -92,8 +92,20 @@ 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 { MemKind::Const(Fun::new(sym, xf).await.to_expr()) });
|
||||
let fac = LazyMemberFactory::new(move |sym| async {
|
||||
return MemKind::Const(build_lambdas(Fun::new(sym, xf).await, 0));
|
||||
fn build_lambdas(fun: Fun, i: u64) -> GExpr {
|
||||
if i < fun.arity().into() {
|
||||
return lambda(i, [build_lambdas(fun, i + 1)]);
|
||||
}
|
||||
let arity = fun.arity();
|
||||
seq(
|
||||
(0..arity)
|
||||
.map(|i| arg(i as u64))
|
||||
.chain([call([fun.to_expr()].into_iter().chain((0..arity).map(|i| arg(i as u64))))]),
|
||||
)
|
||||
}
|
||||
});
|
||||
with_export(GenMember { name: name.to_string(), kind: MemKind::Lazy(fac) }, exported)
|
||||
}
|
||||
pub fn macro_block(prio: Option<f64>, rules: impl IntoIterator<Item = Rule>) -> Vec<GenItem> {
|
||||
|
||||
Reference in New Issue
Block a user