New macro system and stdlib additions

This commit is contained in:
2025-11-21 14:25:03 +01:00
parent b77653f841
commit 603efef28e
230 changed files with 3033 additions and 16640 deletions

View File

@@ -12,21 +12,20 @@ use futures::future::LocalBoxFuture;
use futures::{AsyncRead, AsyncWrite, FutureExt, StreamExt, stream};
use orchid_api_derive::Coding;
use orchid_api_traits::{Coding, Decode, Encode, Request, enc_vec};
use orchid_base::clone;
use orchid_base::error::{OrcErrv, OrcRes, mk_errv, mk_errv_floating};
use orchid_base::format::{FmtCtx, FmtUnit, Format};
use orchid_base::interner::Interner;
use orchid_base::format::{FmtCtx, FmtUnit, Format, fmt};
use orchid_base::location::Pos;
use orchid_base::name::Sym;
use orchid_base::reqnot::Requester;
use trait_set::trait_set;
use crate::api;
use crate::context::{ctx, i};
use crate::conv::ToExpr;
// use crate::error::{ProjectError, ProjectResult};
use crate::expr::{Expr, ExprData, ExprHandle, ExprKind};
use crate::gen_expr::GExpr;
use crate::system::{DynSystemCard, SysCtx, atom_info_for, downcast_atom};
use crate::system::{DynSystemCard, atom_info_for, downcast_atom};
#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Coding)]
pub struct AtomTypeId(pub NonZeroU32);
@@ -91,19 +90,18 @@ pub struct ForeignAtom {
}
impl ForeignAtom {
pub fn pos(&self) -> Pos { self.pos.clone() }
pub fn ctx(&self) -> &SysCtx { &self.expr.ctx }
pub fn ex(self) -> Expr {
let (handle, pos) = (self.expr.clone(), self.pos.clone());
let data = ExprData { pos, kind: ExprKind::Atom(ForeignAtom { ..self }) };
Expr::new(handle, data)
Expr::from_data(handle, data)
}
pub(crate) fn new(handle: Rc<ExprHandle>, atom: api::Atom, pos: Pos) -> Self {
ForeignAtom { atom, expr: handle, pos }
}
pub async fn request<M: AtomMethod>(&self, m: M) -> Option<M::Response> {
let rep = (self.ctx().reqnot().request(api::Fwd(
let rep = (ctx().reqnot().request(api::Fwd(
self.atom.clone(),
Sym::parse(M::NAME, self.ctx().i()).await.unwrap().tok().to_api(),
Sym::parse(M::NAME, &i()).await.unwrap().tok().to_api(),
enc_vec(&m).await,
)))
.await?;
@@ -121,40 +119,38 @@ 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(&ctx().reqnot().request(api::ExtAtomPrint(self.atom.clone())).await)
}
}
impl ToExpr for ForeignAtom {
async fn to_expr(self) -> GExpr { self.ex().to_expr().await }
async fn to_gen(self) -> GExpr { self.ex().to_gen().await }
}
pub struct NotTypAtom {
pub pos: Pos,
pub expr: Expr,
pub typ: Box<dyn AtomDynfo>,
pub ctx: SysCtx,
}
impl NotTypAtom {
pub async fn mk_err(&self) -> OrcErrv {
mk_errv(
self.ctx.i().i("Not the expected type").await,
format!("This expression is not a {}", self.typ.name()),
i().i("Not the expected type").await,
format!("The expression {} is not a {}", fmt(&self.expr, &i()).await, self.typ.name()),
[self.pos.clone()],
)
}
}
pub trait AtomMethod: Request {
pub trait AtomMethod: Request + Coding {
const NAME: &str;
}
pub trait Supports<M: AtomMethod>: AtomCard {
fn handle(&self, ctx: SysCtx, req: M) -> impl Future<Output = <M as Request>::Response>;
fn handle(&self, req: M) -> impl Future<Output = <M as Request>::Response>;
}
trait_set! {
trait AtomReqCb<A> = for<'a> Fn(
&'a A,
SysCtx,
Pin<&'a mut dyn AsyncRead>,
Pin<&'a mut dyn AsyncWrite>,
) -> LocalBoxFuture<'a, ()>
@@ -171,24 +167,18 @@ impl<A: AtomCard> MethodSetBuilder<A> {
assert!(!M::NAME.is_empty(), "AtomMethod::NAME cannoot be empty");
self.handlers.push((
M::NAME,
Rc::new(
move |a: &A, ctx: SysCtx, req: Pin<&mut dyn AsyncRead>, rep: Pin<&mut dyn AsyncWrite>| {
async { Supports::<M>::handle(a, ctx, M::decode(req).await).await.encode(rep).await }
.boxed_local()
},
),
Rc::new(move |a: &A, req: Pin<&mut dyn AsyncRead>, rep: Pin<&mut dyn AsyncWrite>| {
async { Supports::<M>::handle(a, M::decode(req).await).await.encode(rep).await }
.boxed_local()
}),
));
self
}
pub async fn pack(&self, ctx: SysCtx) -> MethodSet<A> {
pub async fn pack(&self) -> MethodSet<A> {
MethodSet {
handlers: stream::iter(self.handlers.iter())
.then(|(k, v)| {
clone!(ctx; async move {
(Sym::parse(k, ctx.i()).await.unwrap(), v.clone())
})
})
.then(async |(k, v)| (Sym::parse(k, &i()).await.unwrap(), v.clone()))
.collect()
.await,
}
@@ -202,7 +192,6 @@ impl<A: AtomCard> MethodSet<A> {
pub(crate) async fn dispatch<'a>(
&'a self,
atom: &'a A,
ctx: SysCtx,
key: Sym,
req: Pin<&'a mut dyn AsyncRead>,
rep: Pin<&'a mut dyn AsyncWrite>,
@@ -210,7 +199,7 @@ impl<A: AtomCard> MethodSet<A> {
match self.handlers.get(&key) {
None => false,
Some(handler) => {
handler(atom, ctx, req, rep).await;
handler(atom, req, rep).await;
true
},
}
@@ -228,33 +217,23 @@ pub struct TAtom<A: AtomicFeatures> {
}
impl<A: AtomicFeatures> TAtom<A> {
pub fn ex(&self) -> Expr { self.untyped.clone().ex() }
pub fn ctx(&self) -> &SysCtx { self.untyped.ctx() }
pub fn i(&self) -> &Interner { self.ctx().i() }
pub fn pos(&self) -> Pos { self.untyped.pos() }
pub async fn downcast(expr: Rc<ExprHandle>) -> Result<Self, NotTypAtom> {
match Expr::from_handle(expr).atom().await {
Err(expr) => Err(NotTypAtom {
ctx: expr.handle().get_ctx(),
pos: expr.data().await.pos.clone(),
expr,
typ: Box::new(A::info()),
}),
Err(expr) =>
Err(NotTypAtom { pos: expr.data().await.pos.clone(), expr, typ: Box::new(A::info()) }),
Ok(atm) => match downcast_atom::<A>(atm).await {
Ok(tatom) => Ok(tatom),
Err(fa) => Err(NotTypAtom {
pos: fa.pos.clone(),
ctx: fa.ctx().clone(),
expr: fa.ex(),
typ: Box::new(A::info()),
}),
Err(fa) => Err(NotTypAtom { pos: fa.pos.clone(), expr: fa.ex(), typ: Box::new(A::info()) }),
},
}
}
pub async fn request<M: AtomMethod>(&self, req: M) -> M::Response
where A: Supports<M> {
M::Response::decode(Pin::new(
&mut &(self.untyped.ctx().reqnot().request(api::Fwd(
&mut &(ctx().reqnot().request(api::Fwd(
self.untyped.atom.clone(),
Sym::parse(M::NAME, self.untyped.ctx().i()).await.unwrap().tok().to_api(),
Sym::parse(M::NAME, &i()).await.unwrap().tok().to_api(),
enc_vec(&req).await,
)))
.await
@@ -268,13 +247,15 @@ impl<A: AtomicFeatures> Deref for TAtom<A> {
fn deref(&self) -> &Self::Target { &self.value }
}
impl<A: AtomicFeatures> ToExpr for TAtom<A> {
async fn to_expr(self) -> GExpr { self.untyped.to_expr().await }
async fn to_gen(self) -> GExpr { self.untyped.to_gen().await }
}
impl<A: AtomicFeatures> Format for TAtom<A> {
async fn print<'a>(&'a self, c: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit {
self.untyped.print(c).await
}
}
pub struct AtomCtx<'a>(pub &'a [u8], pub Option<api::AtomId>, pub SysCtx);
impl FmtCtx for AtomCtx<'_> {
fn i(&self) -> &Interner { self.2.i() }
}
pub struct AtomCtx<'a>(pub &'a [u8], pub Option<api::AtomId>);
pub trait AtomDynfo: 'static {
fn tid(&self) -> TypeId;
@@ -296,24 +277,19 @@ pub trait AtomDynfo: 'static {
ctx: AtomCtx<'a>,
write: Pin<&'b mut dyn AsyncWrite>,
) -> LocalBoxFuture<'a, Option<Vec<Expr>>>;
fn deserialize<'a>(
&'a self,
ctx: SysCtx,
data: &'a [u8],
refs: &'a [Expr],
) -> LocalBoxFuture<'a, api::Atom>;
fn deserialize<'a>(&'a self, data: &'a [u8], refs: &'a [Expr]) -> LocalBoxFuture<'a, api::Atom>;
fn drop<'a>(&'a self, ctx: AtomCtx<'a>) -> LocalBoxFuture<'a, ()>;
}
trait_set! {
pub trait AtomFactoryFn = FnOnce(SysCtx) -> LocalBoxFuture<'static, api::Atom> + DynClone;
pub trait AtomFactoryFn = FnOnce() -> LocalBoxFuture<'static, api::Atom> + DynClone;
}
pub struct AtomFactory(Box<dyn AtomFactoryFn>);
impl AtomFactory {
pub fn new(f: impl AsyncFnOnce(SysCtx) -> api::Atom + Clone + 'static) -> Self {
Self(Box::new(|ctx| f(ctx).boxed_local()))
pub fn new(f: impl AsyncFnOnce() -> api::Atom + Clone + 'static) -> Self {
Self(Box::new(|| f().boxed_local()))
}
pub async fn build(self, ctx: SysCtx) -> api::Atom { (self.0)(ctx).await }
pub async fn build(self) -> api::Atom { (self.0)().await }
}
impl Clone for AtomFactory {
fn clone(&self) -> Self { AtomFactory(clone_box(&*self.0)) }
@@ -330,10 +306,10 @@ impl Format for AtomFactory {
}
}
pub async fn err_not_callable(i: &Interner) -> OrcErrv {
mk_errv_floating(i.i("This atom is not callable").await, "Attempted to apply value as function")
pub async fn err_not_callable() -> OrcErrv {
mk_errv_floating(i().i("This atom is not callable").await, "Attempted to apply value as function")
}
pub async fn err_not_command(i: &Interner) -> OrcErrv {
mk_errv_floating(i.i("This atom is not a command").await, "Settled on an inactionable value")
pub async fn err_not_command() -> OrcErrv {
mk_errv_floating(i().i("This atom is not a command").await, "Settled on an inactionable value")
}