forked from Orchid/orchid
commit before easter break
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
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;
|
||||
@@ -22,7 +21,6 @@ use orchid_base::interner::Interner;
|
||||
use orchid_base::location::Pos;
|
||||
use orchid_base::name::Sym;
|
||||
use orchid_base::reqnot::Requester;
|
||||
use orchid_base::tree::AtomRepr;
|
||||
use trait_set::trait_set;
|
||||
|
||||
use crate::api;
|
||||
@@ -44,12 +42,8 @@ pub trait Atomic: 'static + Sized {
|
||||
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>;
|
||||
/// participate in IPC at all, the default implementation is fine
|
||||
fn reg_reqs() -> MethodSetBuilder<Self> { MethodSetBuilder::new() }
|
||||
}
|
||||
impl<A: Atomic> AtomCard for A {
|
||||
type Data = <Self as Atomic>::Data;
|
||||
@@ -91,57 +85,43 @@ pub fn get_info<A: AtomCard>(
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ForeignAtom<'a> {
|
||||
pub(crate) expr: Option<Rc<ExprHandle>>,
|
||||
pub(crate) _life: PhantomData<&'a ()>,
|
||||
pub(crate) ctx: SysCtx,
|
||||
pub struct ForeignAtom {
|
||||
pub(crate) expr: Rc<ExprHandle>,
|
||||
pub(crate) atom: api::Atom,
|
||||
pub(crate) pos: Pos,
|
||||
}
|
||||
impl ForeignAtom<'_> {
|
||||
pub fn ex_opt(self) -> Option<Expr> {
|
||||
let (handle, pos) = (self.expr.as_ref()?.clone(), self.pos.clone());
|
||||
let data = ExprData { pos, kind: ExprKind::Atom(ForeignAtom { _life: PhantomData, ..self }) };
|
||||
Some(Expr::new(handle, data))
|
||||
}
|
||||
impl ForeignAtom {
|
||||
pub fn pos(&self) -> Pos { self.pos.clone() }
|
||||
pub fn ctx(&self) -> SysCtx { self.ctx.clone() }
|
||||
}
|
||||
impl ForeignAtom<'static> {
|
||||
pub fn ex(self) -> Expr { self.ex_opt().unwrap() }
|
||||
pub fn ctx(&self) -> SysCtx { self.expr.ctx.clone() }
|
||||
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)
|
||||
}
|
||||
pub(crate) fn new(handle: Rc<ExprHandle>, atom: api::Atom, pos: Pos) -> Self {
|
||||
ForeignAtom { _life: PhantomData, atom, ctx: handle.ctx.clone(), expr: Some(handle), pos }
|
||||
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 = (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?;
|
||||
Some(M::Response::decode(Pin::new(&mut &rep[..])).await)
|
||||
}
|
||||
}
|
||||
impl fmt::Display for ForeignAtom<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}::{:?}", if self.expr.is_some() { "Clause" } else { "Tok" }, self.atom)
|
||||
}
|
||||
impl fmt::Display for ForeignAtom {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Atom::{:?}", self.atom) }
|
||||
}
|
||||
impl fmt::Debug for ForeignAtom<'_> {
|
||||
impl fmt::Debug for ForeignAtom {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "ForeignAtom({self})") }
|
||||
}
|
||||
impl Format 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<'_> {
|
||||
type Ctx = SysCtx;
|
||||
async fn from_api(atom: &api::Atom, pos: Pos, ctx: &mut Self::Ctx) -> Self {
|
||||
Self { atom: atom.clone(), _life: PhantomData, ctx: ctx.clone(), expr: None, pos }
|
||||
}
|
||||
async fn to_api(&self) -> orchid_api::Atom { self.atom.clone() }
|
||||
}
|
||||
|
||||
pub struct NotTypAtom {
|
||||
pub pos: Pos,
|
||||
@@ -235,11 +215,11 @@ impl<A: AtomCard> Default for MethodSetBuilder<A> {
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct TypAtom<'a, A: AtomicFeatures> {
|
||||
pub data: ForeignAtom<'a>,
|
||||
pub struct TypAtom<A: AtomicFeatures> {
|
||||
pub data: ForeignAtom,
|
||||
pub value: A::Data,
|
||||
}
|
||||
impl<A: AtomicFeatures> TypAtom<'static, A> {
|
||||
impl<A: AtomicFeatures> TypAtom<A> {
|
||||
pub async fn downcast(expr: Rc<ExprHandle>) -> Result<Self, NotTypAtom> {
|
||||
match Expr::from_handle(expr).atom().await {
|
||||
Err(expr) => Err(NotTypAtom {
|
||||
@@ -252,21 +232,19 @@ impl<A: AtomicFeatures> TypAtom<'static, A> {
|
||||
Ok(tatom) => Ok(tatom),
|
||||
Err(fa) => Err(NotTypAtom {
|
||||
pos: fa.pos.clone(),
|
||||
ctx: fa.ctx.clone(),
|
||||
ctx: fa.ctx().clone(),
|
||||
expr: fa.ex(),
|
||||
typ: Box::new(A::info()),
|
||||
}),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
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 +253,7 @@ impl<A: AtomicFeatures> TypAtom<'_, A> {
|
||||
.await
|
||||
}
|
||||
}
|
||||
impl<A: AtomicFeatures> Deref for TypAtom<'_, A> {
|
||||
impl<A: AtomicFeatures> Deref for TypAtom<A> {
|
||||
type Target = A::Data;
|
||||
fn deref(&self) -> &Self::Target { &self.value }
|
||||
}
|
||||
@@ -289,8 +267,8 @@ pub trait AtomDynfo: 'static {
|
||||
fn tid(&self) -> TypeId;
|
||||
fn name(&self) -> &'static str;
|
||||
fn decode<'a>(&'a self, ctx: AtomCtx<'a>) -> LocalBoxFuture<'a, Box<dyn Any>>;
|
||||
fn call<'a>(&'a self, ctx: AtomCtx<'a>, arg: api::ExprTicket) -> LocalBoxFuture<'a, GExpr>;
|
||||
fn call_ref<'a>(&'a self, ctx: AtomCtx<'a>, arg: api::ExprTicket) -> LocalBoxFuture<'a, GExpr>;
|
||||
fn call<'a>(&'a self, ctx: AtomCtx<'a>, arg: Expr) -> LocalBoxFuture<'a, GExpr>;
|
||||
fn call_ref<'a>(&'a self, ctx: AtomCtx<'a>, arg: Expr) -> LocalBoxFuture<'a, GExpr>;
|
||||
fn print<'a>(&'a self, ctx: AtomCtx<'a>) -> LocalBoxFuture<'a, FmtUnit>;
|
||||
fn handle_req<'a, 'b: 'a, 'c: 'a>(
|
||||
&'a self,
|
||||
@@ -304,12 +282,12 @@ pub trait AtomDynfo: 'static {
|
||||
&'a self,
|
||||
ctx: AtomCtx<'a>,
|
||||
write: Pin<&'b mut dyn Write>,
|
||||
) -> LocalBoxFuture<'a, Option<Vec<api::ExprTicket>>>;
|
||||
) -> LocalBoxFuture<'a, Option<Vec<Expr>>>;
|
||||
fn deserialize<'a>(
|
||||
&'a self,
|
||||
ctx: SysCtx,
|
||||
data: &'a [u8],
|
||||
refs: &'a [api::ExprTicket],
|
||||
refs: &'a [Expr],
|
||||
) -> LocalBoxFuture<'a, api::Atom>;
|
||||
fn drop<'a>(&'a self, ctx: AtomCtx<'a>) -> LocalBoxFuture<'a, ()>;
|
||||
}
|
||||
@@ -319,9 +297,7 @@ trait_set! {
|
||||
}
|
||||
pub struct AtomFactory(Box<dyn AtomFactoryFn>);
|
||||
impl AtomFactory {
|
||||
pub fn new(
|
||||
f: impl AsyncFnOnce(SysCtx) -> api::Atom + Clone + 'static,
|
||||
) -> Self {
|
||||
pub fn new(f: impl AsyncFnOnce(SysCtx) -> api::Atom + Clone + 'static) -> Self {
|
||||
Self(Box::new(|ctx| f(ctx).boxed_local()))
|
||||
}
|
||||
pub async fn build(self, ctx: SysCtx) -> api::Atom { (self.0)(ctx).await }
|
||||
|
||||
@@ -4,7 +4,6 @@ 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;
|
||||
@@ -18,7 +17,7 @@ use never::Never;
|
||||
use orchid_api::AtomId;
|
||||
use orchid_api_traits::{Decode, Encode, enc_vec};
|
||||
use orchid_base::error::OrcRes;
|
||||
use orchid_base::format::FmtUnit;
|
||||
use orchid_base::format::{FmtCtx, FmtCtxImpl, FmtUnit};
|
||||
use orchid_base::name::Sym;
|
||||
|
||||
use crate::api;
|
||||
@@ -26,7 +25,7 @@ use crate::atom::{
|
||||
AtomCard, AtomCtx, AtomDynfo, AtomFactory, Atomic, AtomicFeaturesImpl, AtomicVariant, MethodSet,
|
||||
MethodSetBuilder, err_not_callable, err_not_command, get_info,
|
||||
};
|
||||
use crate::expr::{Expr, ExprHandle};
|
||||
use crate::expr::Expr;
|
||||
use crate::gen_expr::{GExpr, bot};
|
||||
use crate::system::{SysCtx, SysCtxEntry};
|
||||
use crate::system_ctor::CtedObj;
|
||||
@@ -86,17 +85,15 @@ impl<T: OwnedAtom> AtomDynfo for OwnedAtomDynfo<T> {
|
||||
Box::new(<T as AtomCard>::Data::decode(Pin::new(&mut &data[..])).await) as Box<dyn Any>
|
||||
})
|
||||
}
|
||||
fn call(&self, AtomCtx(_, id, ctx): AtomCtx, arg: api::ExprTicket) -> LocalBoxFuture<'_, GExpr> {
|
||||
Box::pin(async move { take_atom(id.unwrap(), &ctx).await.dyn_call(ctx.clone(), arg).await })
|
||||
fn call(&self, AtomCtx(_, id, ctx): AtomCtx, arg: Expr) -> LocalBoxFuture<'_, GExpr> {
|
||||
Box::pin(async move { take_atom(id.unwrap(), &ctx).await.dyn_call(arg).await })
|
||||
}
|
||||
fn call_ref<'a>(
|
||||
&'a self,
|
||||
AtomCtx(_, id, ctx): AtomCtx<'a>,
|
||||
arg: api::ExprTicket,
|
||||
arg: Expr,
|
||||
) -> LocalBoxFuture<'a, GExpr> {
|
||||
Box::pin(async move {
|
||||
AtomReadGuard::new(id.unwrap(), &ctx).await.dyn_call_ref(ctx.clone(), arg).await
|
||||
})
|
||||
Box::pin(async move { AtomReadGuard::new(id.unwrap(), &ctx).await.dyn_call_ref(arg).await })
|
||||
}
|
||||
fn print(&self, AtomCtx(_, id, ctx): AtomCtx<'_>) -> LocalBoxFuture<'_, FmtUnit> {
|
||||
Box::pin(
|
||||
@@ -129,24 +126,22 @@ impl<T: OwnedAtom> AtomDynfo for OwnedAtomDynfo<T> {
|
||||
&'a self,
|
||||
AtomCtx(_, id, ctx): AtomCtx<'a>,
|
||||
mut write: Pin<&'b mut dyn Write>,
|
||||
) -> LocalBoxFuture<'a, Option<Vec<api::ExprTicket>>> {
|
||||
) -> LocalBoxFuture<'a, Option<Vec<Expr>>> {
|
||||
Box::pin(async move {
|
||||
let id = id.unwrap();
|
||||
id.encode(write.as_mut()).await;
|
||||
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())
|
||||
AtomReadGuard::new(id, &ctx).await.dyn_serialize(ctx.clone(), write).await
|
||||
})
|
||||
}
|
||||
fn deserialize<'a>(
|
||||
&'a self,
|
||||
ctx: SysCtx,
|
||||
data: &'a [u8],
|
||||
refs: &'a [api::ExprTicket],
|
||||
refs: &'a [Expr],
|
||||
) -> LocalBoxFuture<'a, api::Atom> {
|
||||
Box::pin(async move {
|
||||
let refs =
|
||||
refs.iter().map(|tk| Expr::from_handle(Rc::new(ExprHandle::from_args(ctx.clone(), *tk))));
|
||||
let obj = T::deserialize(DeserCtxImpl(data, &ctx), T::Refs::from_iter(refs)).await;
|
||||
let refs = T::Refs::from_iter(refs.iter().cloned());
|
||||
let obj = T::deserialize(DeserCtxImpl(data, &ctx), refs).await;
|
||||
obj._factory().build(ctx).await
|
||||
})
|
||||
}
|
||||
@@ -220,12 +215,12 @@ pub trait OwnedAtom: Atomic<Variant = OwnedVariant> + Any + Clone + 'static {
|
||||
type Refs: RefSet;
|
||||
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]) }
|
||||
fn call_ref(&self, arg: Expr) -> impl Future<Output = GExpr> {
|
||||
async move { bot([err_not_callable(arg.ctx().i()).await]) }
|
||||
}
|
||||
fn call(self, arg: ExprHandle) -> impl Future<Output = GExpr> {
|
||||
fn call(self, arg: Expr) -> impl Future<Output = GExpr> {
|
||||
async {
|
||||
let ctx = arg.get_ctx();
|
||||
let ctx = arg.ctx();
|
||||
let gcl = self.call_ref(arg).await;
|
||||
self.free(ctx).await;
|
||||
gcl
|
||||
@@ -238,7 +233,7 @@ pub trait OwnedAtom: Atomic<Variant = OwnedVariant> + Any + Clone + 'static {
|
||||
#[allow(unused_variables)]
|
||||
fn free(self, ctx: SysCtx) -> impl Future<Output = ()> { async {} }
|
||||
#[allow(unused_variables)]
|
||||
fn print(&self, ctx: SysCtx) -> impl Future<Output = FmtUnit> {
|
||||
fn print<'a>(&'a self, c: &'a (impl FmtCtx + ?Sized + 'a)) -> impl Future<Output = FmtUnit> {
|
||||
async { format!("OwnedAtom({})", type_name::<Self>()).into() }
|
||||
}
|
||||
#[allow(unused_variables)]
|
||||
@@ -268,9 +263,8 @@ pub trait DynOwnedAtom: 'static {
|
||||
fn atom_tid(&self) -> TypeId;
|
||||
fn as_any_ref(&self) -> &dyn Any;
|
||||
fn encode<'a>(&'a self, buffer: Pin<&'a mut dyn Write>) -> LocalBoxFuture<'a, ()>;
|
||||
fn dyn_call_ref(&self, ctx: SysCtx, arg: api::ExprTicket) -> LocalBoxFuture<'_, GExpr>;
|
||||
fn dyn_call(self: Box<Self>, ctx: SysCtx, arg: api::ExprTicket)
|
||||
-> LocalBoxFuture<'static, GExpr>;
|
||||
fn dyn_call_ref(&self, arg: Expr) -> LocalBoxFuture<'_, GExpr>;
|
||||
fn dyn_call(self: Box<Self>, arg: Expr) -> LocalBoxFuture<'static, GExpr>;
|
||||
fn dyn_command(self: Box<Self>, ctx: SysCtx) -> LocalBoxFuture<'static, OrcRes<Option<GExpr>>>;
|
||||
fn dyn_free(self: Box<Self>, ctx: SysCtx) -> LocalBoxFuture<'static, ()>;
|
||||
fn dyn_print(&self, ctx: SysCtx) -> LocalBoxFuture<'_, FmtUnit>;
|
||||
@@ -286,15 +280,11 @@ impl<T: OwnedAtom> DynOwnedAtom for T {
|
||||
fn encode<'a>(&'a self, buffer: Pin<&'a mut dyn Write>) -> LocalBoxFuture<'a, ()> {
|
||||
async { self.val().await.as_ref().encode(buffer).await }.boxed_local()
|
||||
}
|
||||
fn dyn_call_ref(&self, ctx: SysCtx, arg: api::ExprTicket) -> LocalBoxFuture<'_, GExpr> {
|
||||
self.call_ref(ExprHandle::from_args(ctx, arg)).boxed_local()
|
||||
fn dyn_call_ref(&self, arg: Expr) -> LocalBoxFuture<'_, GExpr> {
|
||||
self.call_ref(arg).boxed_local()
|
||||
}
|
||||
fn dyn_call(
|
||||
self: Box<Self>,
|
||||
ctx: SysCtx,
|
||||
arg: api::ExprTicket,
|
||||
) -> LocalBoxFuture<'static, GExpr> {
|
||||
self.call(ExprHandle::from_args(ctx, arg)).boxed_local()
|
||||
fn dyn_call(self: Box<Self>, arg: Expr) -> LocalBoxFuture<'static, GExpr> {
|
||||
self.call(arg).boxed_local()
|
||||
}
|
||||
fn dyn_command(self: Box<Self>, ctx: SysCtx) -> LocalBoxFuture<'static, OrcRes<Option<GExpr>>> {
|
||||
self.command(ctx).boxed_local()
|
||||
@@ -302,7 +292,9 @@ impl<T: OwnedAtom> DynOwnedAtom for T {
|
||||
fn dyn_free(self: Box<Self>, ctx: SysCtx) -> LocalBoxFuture<'static, ()> {
|
||||
self.free(ctx).boxed_local()
|
||||
}
|
||||
fn dyn_print(&self, ctx: SysCtx) -> LocalBoxFuture<'_, FmtUnit> { self.print(ctx).boxed_local() }
|
||||
fn dyn_print(&self, ctx: SysCtx) -> LocalBoxFuture<'_, FmtUnit> {
|
||||
async move { self.print(&FmtCtxImpl { i: ctx.i() }).await }.boxed_local()
|
||||
}
|
||||
fn dyn_serialize<'a>(
|
||||
&'a self,
|
||||
ctx: SysCtx,
|
||||
|
||||
@@ -16,7 +16,7 @@ use crate::atom::{
|
||||
AtomCard, AtomCtx, AtomDynfo, AtomFactory, Atomic, AtomicFeaturesImpl, AtomicVariant, MethodSet,
|
||||
MethodSetBuilder, err_not_callable, err_not_command, get_info,
|
||||
};
|
||||
use crate::expr::ExprHandle;
|
||||
use crate::expr::Expr;
|
||||
use crate::gen_expr::{GExpr, bot};
|
||||
use crate::system::SysCtx;
|
||||
use crate::system_ctor::CtedObj;
|
||||
@@ -49,23 +49,11 @@ impl<T: ThinAtom> AtomDynfo for ThinAtomDynfo<T> {
|
||||
fn decode<'a>(&'a self, AtomCtx(buf, ..): AtomCtx<'a>) -> LocalBoxFuture<'a, Box<dyn Any>> {
|
||||
Box::pin(async { Box::new(T::decode(Pin::new(&mut &buf[..])).await) as Box<dyn Any> })
|
||||
}
|
||||
fn call<'a>(
|
||||
&'a self,
|
||||
AtomCtx(buf, _, ctx): AtomCtx<'a>,
|
||||
arg: api::ExprTicket,
|
||||
) -> LocalBoxFuture<'a, GExpr> {
|
||||
Box::pin(async move {
|
||||
T::decode(Pin::new(&mut &buf[..])).await.call(ExprHandle::from_args(ctx, arg)).await
|
||||
})
|
||||
fn call<'a>(&'a self, AtomCtx(buf, ..): AtomCtx<'a>, arg: Expr) -> LocalBoxFuture<'a, GExpr> {
|
||||
Box::pin(async move { T::decode(Pin::new(&mut &buf[..])).await.call(arg).await })
|
||||
}
|
||||
fn call_ref<'a>(
|
||||
&'a self,
|
||||
AtomCtx(buf, _, ctx): AtomCtx<'a>,
|
||||
arg: api::ExprTicket,
|
||||
) -> LocalBoxFuture<'a, GExpr> {
|
||||
Box::pin(async move {
|
||||
T::decode(Pin::new(&mut &buf[..])).await.call(ExprHandle::from_args(ctx, arg)).await
|
||||
})
|
||||
fn call_ref<'a>(&'a self, AtomCtx(buf, ..): AtomCtx<'a>, arg: Expr) -> LocalBoxFuture<'a, GExpr> {
|
||||
Box::pin(async move { T::decode(Pin::new(&mut &buf[..])).await.call(arg).await })
|
||||
}
|
||||
fn handle_req<'a, 'm1: 'a, 'm2: 'a>(
|
||||
&'a self,
|
||||
@@ -89,7 +77,7 @@ impl<T: ThinAtom> AtomDynfo for ThinAtomDynfo<T> {
|
||||
&'a self,
|
||||
ctx: AtomCtx<'a>,
|
||||
write: Pin<&'b mut dyn Write>,
|
||||
) -> LocalBoxFuture<'a, Option<Vec<api::ExprTicket>>> {
|
||||
) -> LocalBoxFuture<'a, Option<Vec<Expr>>> {
|
||||
Box::pin(async {
|
||||
T::decode(Pin::new(&mut &ctx.0[..])).await.encode(write).await;
|
||||
Some(Vec::new())
|
||||
@@ -99,7 +87,7 @@ impl<T: ThinAtom> AtomDynfo for ThinAtomDynfo<T> {
|
||||
&'a self,
|
||||
ctx: SysCtx,
|
||||
data: &'a [u8],
|
||||
refs: &'a [api::ExprTicket],
|
||||
refs: &'a [Expr],
|
||||
) -> LocalBoxFuture<'a, api::Atom> {
|
||||
assert!(refs.is_empty(), "Refs found when deserializing thin atom");
|
||||
Box::pin(async { T::decode(Pin::new(&mut &data[..])).await._factory().build(ctx).await })
|
||||
@@ -116,8 +104,8 @@ pub trait ThinAtom:
|
||||
AtomCard<Data = Self> + Atomic<Variant = ThinVariant> + Coding + Send + Sync + 'static
|
||||
{
|
||||
#[allow(unused_variables)]
|
||||
fn call(&self, arg: ExprHandle) -> impl Future<Output = GExpr> {
|
||||
async move { bot([err_not_callable(arg.ctx.i()).await]) }
|
||||
fn call(&self, arg: Expr) -> impl Future<Output = GExpr> {
|
||||
async move { bot([err_not_callable(arg.ctx().i()).await]) }
|
||||
}
|
||||
#[allow(unused_variables)]
|
||||
fn command(&self, ctx: SysCtx) -> impl Future<Output = OrcRes<Option<GExpr>>> {
|
||||
|
||||
@@ -31,7 +31,7 @@ async fn err_type(pos: Pos, i: &Interner) -> OrcErr {
|
||||
mk_err(i.i("Type error").await, "The atom is a different type than expected", [pos.into()])
|
||||
}
|
||||
|
||||
impl<A: AtomicFeatures> TryFromExpr for TypAtom<'_, A> {
|
||||
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()),
|
||||
@@ -51,7 +51,7 @@ impl ToExpr for GExpr {
|
||||
fn to_expr(self) -> GExpr { self }
|
||||
}
|
||||
impl ToExpr for Expr {
|
||||
fn to_expr(self) -> GExpr { self.gen() }
|
||||
fn to_expr(self) -> GExpr { self.slot() }
|
||||
}
|
||||
|
||||
impl<T: ToExpr> ToExpr for OrcRes<T> {
|
||||
|
||||
@@ -12,30 +12,29 @@ use futures::future::{LocalBoxFuture, join_all};
|
||||
use futures::{FutureExt, StreamExt, stream_select};
|
||||
use hashbrown::HashMap;
|
||||
use itertools::Itertools;
|
||||
use orchid_api::{ApplyMacro, ExtMsgSet};
|
||||
use orchid_api_traits::{Decode, enc_vec};
|
||||
use orchid_api::{ExtMsgSet, IntReq};
|
||||
use orchid_api_traits::{Decode, UnderRoot, enc_vec};
|
||||
use orchid_base::builtin::{ExtInit, ExtPort, Spawner};
|
||||
use orchid_base::char_filter::{char_filter_match, char_filter_union, mk_char_filter};
|
||||
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::Sym;
|
||||
use orchid_base::parse::{Comment, Snippet};
|
||||
use orchid_base::reqnot::{ReqNot, RequestHandle, Requester};
|
||||
use orchid_base::tree::{ttv_from_api, ttv_to_api};
|
||||
use orchid_base::tree::{TokenVariant, ttv_from_api, ttv_into_api};
|
||||
use substack::Substack;
|
||||
use trait_set::trait_set;
|
||||
|
||||
use crate::api;
|
||||
use crate::atom::{AtomCtx, AtomDynfo, AtomTypeId};
|
||||
use crate::atom_owned::take_atom;
|
||||
use crate::expr::{Expr, ExprHandle};
|
||||
use crate::fs::VirtFS;
|
||||
use crate::lexer::{LexContext, err_cascade, err_not_applicable};
|
||||
use crate::macros::{Rule, RuleCtx};
|
||||
use crate::system::{SysCtx, atom_by_idx};
|
||||
use crate::system_ctor::{CtedObj, DynSystemCtor};
|
||||
use crate::tree::{GenTok, GenTokTree, LazyMemberFactory, TreeIntoApiCtxImpl, do_extra};
|
||||
use crate::tree::{GenItemKind, GenTok, GenTokTree, LazyMemberFactory, TreeIntoApiCtxImpl};
|
||||
|
||||
pub type ExtReq<'a> = RequestHandle<'a, api::ExtMsgSet>;
|
||||
pub type ExtReqNot = ReqNot<api::ExtMsgSet>;
|
||||
@@ -60,7 +59,6 @@ pub struct SystemRecord {
|
||||
vfses: HashMap<api::VfsId, &'static dyn VirtFS>,
|
||||
declfs: api::EagerVfs,
|
||||
lazy_members: HashMap<api::TreeId, MemberRecord>,
|
||||
rules: HashMap<api::MacroId, Rc<Rule>>,
|
||||
ctx: SysCtx,
|
||||
}
|
||||
|
||||
@@ -197,16 +195,17 @@ pub fn extension_init(
|
||||
char_filter_union(&cf, &mk_char_filter(lx.char_filter().iter().cloned()))
|
||||
});
|
||||
let lazy_mems = Mutex::new(HashMap::new());
|
||||
let rules = Mutex::new(HashMap::new());
|
||||
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);
|
||||
.filter_map(
|
||||
async |i| if let GenItemKind::Member(m) = i.kind { Some(m) } else { None },
|
||||
)
|
||||
.then(|mem| {
|
||||
let (req, lazy_mems) = (&hand, &lazy_mems);
|
||||
clone!(i, ctx; async move {
|
||||
let name = i.i(&k).await.to_api();
|
||||
let value = v.into_api(&mut TreeIntoApiCtxImpl {
|
||||
let name = i.i(&mem.name).await.to_api();
|
||||
let value = mem.kind.into_api(&mut TreeIntoApiCtxImpl {
|
||||
lazy_members: &mut *lazy_mems.lock().await,
|
||||
rules: &mut *rules.lock().await,
|
||||
sys: ctx,
|
||||
basepath: &[],
|
||||
path: Substack::Bottom,
|
||||
@@ -219,24 +218,23 @@ pub fn extension_init(
|
||||
.collect()
|
||||
.await;
|
||||
let declfs = cted.inst().dyn_vfs().to_api_rec(&mut vfses, &i).await;
|
||||
let record = SystemRecord {
|
||||
declfs,
|
||||
vfses,
|
||||
ctx,
|
||||
lazy_members: lazy_mems.into_inner(),
|
||||
rules: rules.into_inner(),
|
||||
};
|
||||
let record =
|
||||
SystemRecord { declfs, vfses, ctx, lazy_members: lazy_mems.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![] })
|
||||
.handle(&new_sys, &api::NewSystemResponse {
|
||||
lex_filter,
|
||||
const_root,
|
||||
line_types: vec![],
|
||||
})
|
||||
.await
|
||||
},
|
||||
api::HostExtReq::GetMember(get_tree @ api::GetMember(sys_id, tree_id)) => {
|
||||
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, .. } =
|
||||
let SystemRecord { lazy_members, .. } =
|
||||
systems_g.get_mut(&sys_id).expect("System not found");
|
||||
let (path, cb) = match lazy_members.insert(tree_id, MemberRecord::Res) {
|
||||
None => panic!("Tree for ID not found"),
|
||||
@@ -249,7 +247,6 @@ pub fn extension_init(
|
||||
path: Substack::Bottom,
|
||||
basepath: &path,
|
||||
lazy_members,
|
||||
rules,
|
||||
req: &hand,
|
||||
};
|
||||
hand.handle(&get_tree, &tree.into_api(&mut tia_ctx).await).await
|
||||
@@ -277,7 +274,7 @@ pub fn extension_init(
|
||||
api::HostExtReq::LexExpr(lex @ api::LexExpr { sys, text, pos, id }) => {
|
||||
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 ctx = LexContext { id, pos, text: &text, ctx: sys_ctx.clone() };
|
||||
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;
|
||||
@@ -290,8 +287,7 @@ pub fn extension_init(
|
||||
return hand.handle(&lex, &eopt).await;
|
||||
},
|
||||
Ok((s, expr)) => {
|
||||
let expr =
|
||||
expr.to_api(&mut async |f, r| do_extra(f, r, sys_ctx.clone()).await).await;
|
||||
let expr = expr.into_api(&mut (), &mut (sys_ctx, &hand)).await;
|
||||
let pos = (text.len() - s.len()) as u32;
|
||||
return hand.handle(&lex, &Some(Ok(api::LexedExpr { pos, expr }))).await;
|
||||
},
|
||||
@@ -301,25 +297,21 @@ pub fn extension_init(
|
||||
hand.handle(&lex, &None).await
|
||||
},
|
||||
api::HostExtReq::ParseLine(pline) => {
|
||||
let api::ParseLine { exported, comments, sys, line } = &pline;
|
||||
let api::ParseLine { module, exported, comments, sys, line } = &pline;
|
||||
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);
|
||||
let line: Vec<GenTokTree> = ttv_from_api(line, &mut ctx, &mut (), &i).await;
|
||||
let snip = Snippet::new(line.first().expect("Empty line"), &line);
|
||||
let (head, tail) = snip.pop_front().unwrap();
|
||||
let name = if let GenTok::Name(n) = &head.tok { n } else { panic!("No line head") };
|
||||
let parser =
|
||||
parsers.iter().find(|p| p.line_head() == **name).expect("No parser candidate");
|
||||
let o_line = match parser.parse(*exported, comments, tail) {
|
||||
let module = Sym::from_api(*module, ctx.i()).await;
|
||||
let o_line = match parser.parse(ctx.clone(), module, *exported, comments, tail).await
|
||||
{
|
||||
Err(e) => Err(e.to_api()),
|
||||
Ok(t) => Ok(
|
||||
ttv_to_api(t, &mut async move |f, range| api::TokenTree {
|
||||
range,
|
||||
token: api::Token::Atom(f.clone().build(ctx.clone()).await),
|
||||
})
|
||||
.await,
|
||||
),
|
||||
Ok(t) => Ok(ttv_into_api(t, &mut (), &mut (ctx.clone(), &hand)).await),
|
||||
};
|
||||
hand.handle(&pline, &o_line).await
|
||||
},
|
||||
@@ -331,8 +323,15 @@ pub fn extension_init(
|
||||
match &atom_req {
|
||||
api::AtomReq::SerializeAtom(ser) => {
|
||||
let mut buf = enc_vec(&id).await;
|
||||
let refs_opt = nfo.serialize(actx, Pin::<&mut Vec<_>>::new(&mut buf)).await;
|
||||
hand.handle(ser, &refs_opt.map(|refs| (buf, refs))).await
|
||||
match nfo.serialize(actx, Pin::<&mut Vec<_>>::new(&mut buf)).await {
|
||||
None => hand.handle(ser, &None).await,
|
||||
Some(refs) => {
|
||||
let refs =
|
||||
join_all(refs.into_iter().map(|ex| async { ex.into_api(&mut ()).await }))
|
||||
.await;
|
||||
hand.handle(ser, &Some((buf, refs))).await
|
||||
},
|
||||
}
|
||||
},
|
||||
api::AtomReq::AtomPrint(print @ api::AtomPrint(_)) =>
|
||||
hand.handle(print, &nfo.print(actx).await.to_api()).await,
|
||||
@@ -351,11 +350,15 @@ pub fn extension_init(
|
||||
hand.handle(fwded, &some.then_some(reply)).await
|
||||
},
|
||||
api::AtomReq::CallRef(call @ api::CallRef(_, arg)) => {
|
||||
let ret = nfo.call_ref(actx, *arg).await;
|
||||
// SAFETY: function calls own their argument implicitly
|
||||
let expr_handle = unsafe { ExprHandle::from_args(ctx.clone(), *arg) };
|
||||
let ret = nfo.call_ref(actx, Expr::from_handle(Rc::new(expr_handle))).await;
|
||||
hand.handle(call, &ret.api_return(ctx.clone(), &hand).await).await
|
||||
},
|
||||
api::AtomReq::FinalCall(call @ api::FinalCall(_, arg)) => {
|
||||
let ret = nfo.call(actx, *arg).await;
|
||||
// SAFETY: function calls own their argument implicitly
|
||||
let expr_handle = unsafe { ExprHandle::from_args(ctx.clone(), *arg) };
|
||||
let ret = nfo.call(actx, Expr::from_handle(Rc::new(expr_handle))).await;
|
||||
hand.handle(call, &ret.api_return(ctx.clone(), &hand).await).await
|
||||
},
|
||||
api::AtomReq::Command(cmd @ api::Command(_)) => match nfo.command(actx).await {
|
||||
@@ -376,41 +379,15 @@ pub fn extension_init(
|
||||
let api::DeserAtom(sys, buf, refs) = &deser;
|
||||
let mut read = &mut &buf[..];
|
||||
let ctx = get_ctx(*sys).await;
|
||||
// SAFETY: deserialization implicitly grants ownership to previously owned exprs
|
||||
let refs = (refs.iter())
|
||||
.map(|tk| unsafe { ExprHandle::from_args(ctx.clone(), *tk) })
|
||||
.map(|handle| Expr::from_handle(Rc::new(handle)))
|
||||
.collect_vec();
|
||||
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
|
||||
},
|
||||
orchid_api::HostExtReq::ApplyMacro(am) => {
|
||||
let tok = hand.will_handle_as(&am);
|
||||
let ApplyMacro { id, params, run_id, sys } = am;
|
||||
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 {
|
||||
ctx.args.insert(
|
||||
Tok::from_api(k, &i).await,
|
||||
mtreev_from_api(&v, &i, &mut async |_| panic!("No atom in macro prompt!")).await,
|
||||
);
|
||||
}
|
||||
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 {
|
||||
Err(e) => {
|
||||
let new_errors = e.keep_only(|e| *e != err_cascade);
|
||||
hand.handle_as(tok, &new_errors.map(|e| Err(e.to_api()))).await
|
||||
},
|
||||
Ok(t) => {
|
||||
clone!(sys_ctx);
|
||||
let result = mtreev_to_api(&t, &mut async |a| {
|
||||
api::MacroToken::Atom(a.clone().build(sys_ctx.clone()).await)
|
||||
})
|
||||
.await;
|
||||
hand.handle_as(tok, &Some(Ok(result))).await
|
||||
},
|
||||
}
|
||||
hand.handle(&deser, &nfo.deserialize(ctx.clone(), read, &refs).await).await
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -418,7 +395,8 @@ pub fn extension_init(
|
||||
}
|
||||
},
|
||||
);
|
||||
*interner_cell.borrow_mut() = Some(Interner::new_replica(rn.clone().map()));
|
||||
*interner_cell.borrow_mut() =
|
||||
Some(Interner::new_replica(rn.clone().map(|ir: IntReq| ir.into_root())));
|
||||
spawner(Box::pin(clone!(spawner; async move {
|
||||
let mut streams = stream_select! { in_recv.map(Some), exit_recv.map(|_| None) };
|
||||
while let Some(item) = streams.next().await {
|
||||
|
||||
@@ -20,12 +20,20 @@ pub struct ExprHandle {
|
||||
pub ctx: SysCtx,
|
||||
}
|
||||
impl ExprHandle {
|
||||
pub(crate) fn from_args(ctx: SysCtx, tk: api::ExprTicket) -> Self { Self { ctx, tk } }
|
||||
/// # Safety
|
||||
///
|
||||
/// This function does not signal to take ownership of the expr. It must only
|
||||
/// be called on tickets that are already implicitly owned.
|
||||
pub unsafe 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.sys_id(), self.tk)).await;
|
||||
Self { ctx: self.ctx.clone(), tk: self.tk }
|
||||
}
|
||||
/// Drop the handle and get the ticket without a release notification.
|
||||
/// Use this with messages that imply ownership transfer. This function is
|
||||
/// safe because abusing it is a memory leak.
|
||||
pub fn into_tk(self) -> api::ExprTicket { self.destructure().0 }
|
||||
}
|
||||
impl fmt::Debug for ExprHandle {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
@@ -66,7 +74,7 @@ impl Expr {
|
||||
}))
|
||||
.await
|
||||
}
|
||||
pub async fn atom(self) -> Result<ForeignAtom<'static>, Self> {
|
||||
pub async fn atom(self) -> Result<ForeignAtom, Self> {
|
||||
match self.data().await {
|
||||
ExprData { kind: ExprKind::Atom(atom), .. } => Ok(atom.clone()),
|
||||
_ => Err(self),
|
||||
@@ -75,7 +83,9 @@ impl Expr {
|
||||
pub fn handle(&self) -> Rc<ExprHandle> { self.handle.clone() }
|
||||
pub fn ctx(&self) -> SysCtx { self.handle.ctx.clone() }
|
||||
|
||||
pub fn gen(&self) -> GExpr { GExpr { pos: Pos::SlotTarget, kind: GExprKind::Slot(self.clone()) } }
|
||||
pub fn slot(&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 {
|
||||
@@ -96,7 +106,7 @@ pub struct ExprData {
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ExprKind {
|
||||
Atom(ForeignAtom<'static>),
|
||||
Atom(ForeignAtom),
|
||||
Bottom(OrcErrv),
|
||||
Opaque,
|
||||
}
|
||||
|
||||
@@ -13,13 +13,14 @@ use never::Never;
|
||||
use orchid_api_traits::Encode;
|
||||
use orchid_base::clone;
|
||||
use orchid_base::error::OrcRes;
|
||||
use orchid_base::format::{FmtCtx, FmtUnit};
|
||||
use orchid_base::name::Sym;
|
||||
use trait_set::trait_set;
|
||||
|
||||
use crate::atom::{Atomic, MethodSetBuilder};
|
||||
use crate::atom_owned::{DeserializeCtx, OwnedAtom, OwnedVariant};
|
||||
use crate::conv::ToExpr;
|
||||
use crate::expr::{Expr, ExprHandle};
|
||||
use crate::expr::Expr;
|
||||
use crate::gen_expr::GExpr;
|
||||
use crate::system::{SysCtx, SysCtxEntry};
|
||||
|
||||
@@ -66,14 +67,13 @@ impl Fun {
|
||||
impl Atomic for Fun {
|
||||
type Data = ();
|
||||
type Variant = OwnedVariant;
|
||||
fn reg_reqs() -> MethodSetBuilder<Self> { MethodSetBuilder::new() }
|
||||
}
|
||||
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 {
|
||||
async fn call_ref(&self, arg: Expr) -> 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();
|
||||
let new_args = self.args.iter().cloned().chain([arg]).collect_vec();
|
||||
if new_args.len() == self.arity.into() {
|
||||
(self.fun)(new_args).await.to_expr()
|
||||
} else {
|
||||
@@ -81,7 +81,7 @@ impl OwnedAtom for Fun {
|
||||
.to_expr()
|
||||
}
|
||||
}
|
||||
async fn call(self, arg: ExprHandle) -> GExpr { self.call_ref(arg).await }
|
||||
async fn call(self, arg: Expr) -> GExpr { self.call_ref(arg).await }
|
||||
async fn serialize(&self, _: SysCtx, write: Pin<&mut (impl Write + ?Sized)>) -> Self::Refs {
|
||||
self.path.to_api().encode(write).await;
|
||||
self.args.clone()
|
||||
@@ -92,7 +92,7 @@ impl OwnedAtom for Fun {
|
||||
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 {
|
||||
async fn print<'a>(&'a self, _: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit {
|
||||
format!("{}:{}/{}", self.path, self.args.len(), self.arity).into()
|
||||
}
|
||||
}
|
||||
@@ -116,20 +116,19 @@ impl Lambda {
|
||||
impl Atomic for Lambda {
|
||||
type Data = ();
|
||||
type Variant = OwnedVariant;
|
||||
fn reg_reqs() -> MethodSetBuilder<Self> { MethodSetBuilder::new() }
|
||||
}
|
||||
impl OwnedAtom for Lambda {
|
||||
type Refs = Never;
|
||||
async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) }
|
||||
async fn call_ref(&self, arg: ExprHandle) -> GExpr {
|
||||
let new_args = self.args.iter().cloned().chain([Expr::from_handle(Rc::new(arg))]).collect_vec();
|
||||
async fn call_ref(&self, arg: Expr) -> GExpr {
|
||||
let new_args = self.args.iter().cloned().chain([arg]).collect_vec();
|
||||
if new_args.len() == self.arity.into() {
|
||||
(self.fun)(new_args).await.to_expr()
|
||||
} else {
|
||||
Self { args: new_args, arity: self.arity, fun: self.fun.clone() }.to_expr()
|
||||
}
|
||||
}
|
||||
async fn call(self, arg: ExprHandle) -> GExpr { self.call_ref(arg).await }
|
||||
async fn call(self, arg: Expr) -> GExpr { self.call_ref(arg).await }
|
||||
}
|
||||
|
||||
mod expr_func_derives {
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
use std::future::Future;
|
||||
use std::rc::Rc;
|
||||
|
||||
use futures::FutureExt;
|
||||
use orchid_base::error::{OrcErr, OrcErrv};
|
||||
use orchid_base::format::{FmtCtx, FmtUnit, Format, Variants};
|
||||
use orchid_base::location::Pos;
|
||||
use orchid_base::match_mapping;
|
||||
use orchid_base::name::Sym;
|
||||
use orchid_base::reqnot::ReqHandlish;
|
||||
use orchid_base::{match_mapping, tl_cache};
|
||||
|
||||
use crate::api;
|
||||
use crate::atom::{AtomFactory, ToAtom};
|
||||
@@ -14,6 +15,7 @@ use crate::expr::Expr;
|
||||
use crate::func_atom::Lambda;
|
||||
use crate::system::SysCtx;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct GExpr {
|
||||
pub kind: GExprKind,
|
||||
pub pos: Pos,
|
||||
@@ -34,7 +36,13 @@ impl GExpr {
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Format for GExpr {
|
||||
async fn print<'a>(&'a self, c: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit {
|
||||
self.kind.print(c).await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum GExprKind {
|
||||
Call(Box<GExpr>, Box<GExpr>),
|
||||
Lambda(u64, Box<GExpr>),
|
||||
@@ -67,6 +75,28 @@ impl GExprKind {
|
||||
})
|
||||
}
|
||||
}
|
||||
impl Format for GExprKind {
|
||||
async fn print<'a>(&'a self, c: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit {
|
||||
match self {
|
||||
GExprKind::Call(f, x) =>
|
||||
tl_cache!(Rc<Variants>: Rc::new(Variants::default().bounded("{0} ({1})")))
|
||||
.units([f.print(c).await, x.print(c).await]),
|
||||
GExprKind::Lambda(arg, body) =>
|
||||
tl_cache!(Rc<Variants>: Rc::new(Variants::default().bounded("\\{0}.{1}")))
|
||||
.units([arg.to_string().into(), body.print(c).await]),
|
||||
GExprKind::Arg(arg) => arg.to_string().into(),
|
||||
GExprKind::Seq(a, b) =>
|
||||
tl_cache!(Rc<Variants>: Rc::new(Variants::default().bounded("[{0}] {1}")))
|
||||
.units([a.print(c).await, b.print(c).await]),
|
||||
GExprKind::Const(sym) => sym.to_string().into(),
|
||||
GExprKind::NewAtom(atom_factory) => atom_factory.to_string().into(),
|
||||
GExprKind::Slot(expr) =>
|
||||
tl_cache!(Rc<Variants>: Rc::new(Variants::default().bounded("{{{0}}}")))
|
||||
.units([expr.print(c).await]),
|
||||
GExprKind::Bottom(orc_errv) => orc_errv.to_string().into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn inherit(kind: GExprKind) -> GExpr { GExpr { pos: Pos::Inherit, kind } }
|
||||
|
||||
|
||||
@@ -6,11 +6,11 @@ use futures::future::LocalBoxFuture;
|
||||
use orchid_base::error::{OrcErr, OrcRes, mk_err};
|
||||
use orchid_base::interner::{Interner, Tok};
|
||||
use orchid_base::location::Pos;
|
||||
use orchid_base::reqnot::{ReqNot, Requester};
|
||||
use orchid_base::tree::TokHandle;
|
||||
use orchid_base::reqnot::Requester;
|
||||
|
||||
use crate::api;
|
||||
use crate::tree::{GenTok, GenTokTree};
|
||||
use crate::system::SysCtx;
|
||||
use crate::tree::GenTokTree;
|
||||
|
||||
pub async fn err_cascade(i: &Interner) -> OrcErr {
|
||||
mk_err(
|
||||
@@ -30,20 +30,19 @@ pub async fn err_not_applicable(i: &Interner) -> OrcErr {
|
||||
}
|
||||
|
||||
pub struct LexContext<'a> {
|
||||
pub ctx: SysCtx,
|
||||
pub text: &'a Tok<String>,
|
||||
pub sys: api::SysId,
|
||||
pub id: api::ParsId,
|
||||
pub pos: u32,
|
||||
pub reqnot: ReqNot<api::ExtMsgSet>,
|
||||
pub i: &'a Interner,
|
||||
}
|
||||
impl<'a> LexContext<'a> {
|
||||
pub async fn recurse(&self, tail: &'a str) -> OrcRes<(&'a str, GenTokTree<'a>)> {
|
||||
pub async fn recurse(&self, tail: &'a str) -> OrcRes<(&'a str, GenTokTree)> {
|
||||
let start = self.pos(tail);
|
||||
let Some(lx) = self.reqnot.request(api::SubLex { pos: start, id: self.id }).await else {
|
||||
return Err(err_cascade(self.i).await.into());
|
||||
let Some(lx) = self.ctx.reqnot().request(api::SubLex { pos: start, id: self.id }).await else {
|
||||
return Err(err_cascade(self.ctx.i()).await.into());
|
||||
};
|
||||
Ok((&self.text[lx.pos as usize..], GenTok::Slot(TokHandle::new(lx.ticket)).at(start..lx.pos)))
|
||||
let tree = GenTokTree::from_api(&lx.tree, &mut self.ctx.clone(), &mut (), self.ctx.i()).await;
|
||||
Ok((&self.text[lx.pos as usize..], tree))
|
||||
}
|
||||
|
||||
pub fn pos(&self, tail: &'a str) -> u32 { (self.text.len() - tail.len()) as u32 }
|
||||
@@ -58,7 +57,7 @@ pub trait Lexer: Send + Sync + Sized + Default + 'static {
|
||||
fn lex<'a>(
|
||||
tail: &'a str,
|
||||
ctx: &'a LexContext<'a>,
|
||||
) -> impl Future<Output = OrcRes<(&'a str, GenTokTree<'a>)>>;
|
||||
) -> impl Future<Output = OrcRes<(&'a str, GenTokTree)>>;
|
||||
}
|
||||
|
||||
pub trait DynLexer: Send + Sync + 'static {
|
||||
@@ -67,7 +66,7 @@ pub trait DynLexer: Send + Sync + 'static {
|
||||
&self,
|
||||
tail: &'a str,
|
||||
ctx: &'a LexContext<'a>,
|
||||
) -> LocalBoxFuture<'a, OrcRes<(&'a str, GenTokTree<'a>)>>;
|
||||
) -> LocalBoxFuture<'a, OrcRes<(&'a str, GenTokTree)>>;
|
||||
}
|
||||
|
||||
impl<T: Lexer> DynLexer for T {
|
||||
@@ -76,7 +75,7 @@ impl<T: Lexer> DynLexer for T {
|
||||
&self,
|
||||
tail: &'a str,
|
||||
ctx: &'a LexContext<'a>,
|
||||
) -> LocalBoxFuture<'a, OrcRes<(&'a str, GenTokTree<'a>)>> {
|
||||
) -> LocalBoxFuture<'a, OrcRes<(&'a str, GenTokTree)>> {
|
||||
T::lex(tail, ctx).boxed_local()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ pub mod fs;
|
||||
pub mod func_atom;
|
||||
pub mod gen_expr;
|
||||
pub mod lexer;
|
||||
pub mod macros;
|
||||
pub mod msg;
|
||||
pub mod other_system;
|
||||
pub mod parser;
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
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::{ReqNot, Requester};
|
||||
use trait_set::trait_set;
|
||||
|
||||
use crate::api;
|
||||
use crate::atom::AtomFactory;
|
||||
use crate::lexer::err_cascade;
|
||||
use crate::system::SysCtx;
|
||||
use crate::tree::TreeIntoApiCtx;
|
||||
|
||||
pub trait Macro {
|
||||
fn pattern() -> MTree<'static, Never>;
|
||||
fn apply(binds: HashMap<Tok<String>, MTree<'_, Never>>) -> MTree<'_, AtomFactory>;
|
||||
}
|
||||
|
||||
pub trait DynMacro {
|
||||
fn pattern(&self) -> MTree<'static, Never>;
|
||||
fn apply<'a>(&self, binds: HashMap<Tok<String>, MTree<'a, Never>>) -> MTree<'a, AtomFactory>;
|
||||
}
|
||||
|
||||
impl<T: Macro> DynMacro for T {
|
||||
fn pattern(&self) -> MTree<'static, Never> { Self::pattern() }
|
||||
fn apply<'a>(&self, binds: HashMap<Tok<String>, MTree<'a, Never>>) -> MTree<'a, AtomFactory> {
|
||||
Self::apply(binds)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RuleCtx<'a> {
|
||||
pub(crate) args: HashMap<Tok<String>, Vec<MTree<'a, Never>>>,
|
||||
pub(crate) run_id: api::ParsId,
|
||||
pub(crate) sys: SysCtx,
|
||||
}
|
||||
impl<'a> RuleCtx<'a> {
|
||||
pub async fn recurse(&mut self, tree: &[MTree<'a, Never>]) -> OrcRes<Vec<MTree<'a, Never>>> {
|
||||
let req = api::RunMacros {
|
||||
run_id: self.run_id,
|
||||
query: mtreev_to_api(tree, &mut async |b| match *b {}).await,
|
||||
};
|
||||
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 async |_| panic!("{ATOM_MSG}")).await)
|
||||
}
|
||||
pub fn getv(&mut self, key: &Tok<String>) -> Vec<MTree<'a, Never>> {
|
||||
self.args.remove(key).expect("Key not found")
|
||||
}
|
||||
pub fn gets(&mut self, key: &Tok<String>) -> MTree<'a, Never> {
|
||||
let v = self.getv(key);
|
||||
assert!(v.len() == 1, "Not a scalar");
|
||||
v.into_iter().next().unwrap()
|
||||
}
|
||||
pub fn unused_arg<'b>(&mut self, keys: impl IntoIterator<Item = &'b Tok<String>>) {
|
||||
keys.into_iter().for_each(|k| {
|
||||
self.getv(k);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
trait_set! {
|
||||
pub trait RuleCB = for<'a> Fn(RuleCtx<'a>) -> LocalBoxFuture<'a, OrcRes<Vec<MTree<'a, AtomFactory>>>>;
|
||||
}
|
||||
|
||||
pub struct Rule {
|
||||
pub(crate) comments: Vec<String>,
|
||||
pub(crate) pattern: Vec<MTree<'static, Never>>,
|
||||
pub(crate) apply: Rc<dyn RuleCB>,
|
||||
}
|
||||
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 }
|
||||
}))
|
||||
.await,
|
||||
location: api::Location::Inherit,
|
||||
pattern: mtreev_to_api(&self.pattern, &mut async |b| match *b {}).await,
|
||||
id: ctx.with_rule(Rc::new(self)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rule_cmt<'a>(
|
||||
cmt: impl IntoIterator<Item = &'a str>,
|
||||
pattern: Vec<MTree<'static, Never>>,
|
||||
apply: impl RuleCB + 'static,
|
||||
) -> Rule {
|
||||
let comments = cmt.into_iter().map(|s| s.to_string()).collect_vec();
|
||||
Rule { comments, pattern, apply: Rc::new(apply) }
|
||||
}
|
||||
|
||||
pub fn rule(pattern: Vec<MTree<'static, Never>>, apply: impl RuleCB + 'static) -> Rule {
|
||||
rule_cmt([], pattern, apply)
|
||||
}
|
||||
@@ -1,39 +1,49 @@
|
||||
use futures::future::LocalBoxFuture;
|
||||
use orchid_base::error::OrcRes;
|
||||
use orchid_base::name::Sym;
|
||||
use orchid_base::parse::{Comment, Snippet};
|
||||
|
||||
use crate::atom::{AtomFactory, ForeignAtom};
|
||||
use crate::expr::Expr;
|
||||
use crate::gen_expr::GExpr;
|
||||
use crate::system::SysCtx;
|
||||
use crate::tree::GenTokTree;
|
||||
|
||||
pub type GenSnippet<'a> = Snippet<'a, 'a, ForeignAtom<'a>, AtomFactory>;
|
||||
pub type GenSnippet<'a> = Snippet<'a, Expr, GExpr>;
|
||||
|
||||
pub trait Parser: Send + Sync + Sized + Default + 'static {
|
||||
const LINE_HEAD: &'static str;
|
||||
fn parse(
|
||||
ctx: SysCtx,
|
||||
module: Sym,
|
||||
exported: bool,
|
||||
comments: Vec<Comment>,
|
||||
line: GenSnippet<'_>,
|
||||
) -> OrcRes<Vec<GenTokTree<'_>>>;
|
||||
) -> impl Future<Output = OrcRes<Vec<GenTokTree>>> + '_;
|
||||
}
|
||||
|
||||
pub trait DynParser: Send + Sync + 'static {
|
||||
fn line_head(&self) -> &'static str;
|
||||
fn parse<'a>(
|
||||
&self,
|
||||
ctx: SysCtx,
|
||||
module: Sym,
|
||||
exported: bool,
|
||||
comments: Vec<Comment>,
|
||||
line: GenSnippet<'a>,
|
||||
) -> OrcRes<Vec<GenTokTree<'a>>>;
|
||||
) -> LocalBoxFuture<'a, OrcRes<Vec<GenTokTree>>>;
|
||||
}
|
||||
|
||||
impl<T: Parser> DynParser for T {
|
||||
fn line_head(&self) -> &'static str { Self::LINE_HEAD }
|
||||
fn parse<'a>(
|
||||
&self,
|
||||
ctx: SysCtx,
|
||||
module: Sym,
|
||||
exported: bool,
|
||||
comments: Vec<Comment>,
|
||||
line: GenSnippet<'a>,
|
||||
) -> OrcRes<Vec<GenTokTree<'a>>> {
|
||||
Self::parse(exported, comments, line)
|
||||
) -> LocalBoxFuture<'a, OrcRes<Vec<GenTokTree>>> {
|
||||
Box::pin(async move { Self::parse(ctx, module, exported, comments, line).await })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ use std::pin::Pin;
|
||||
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};
|
||||
@@ -24,7 +23,7 @@ use crate::func_atom::Fun;
|
||||
use crate::lexer::LexerObj;
|
||||
use crate::parser::ParserObj;
|
||||
use crate::system_ctor::{CtedObj, SystemCtor};
|
||||
use crate::tree::MemKind;
|
||||
use crate::tree::GenItem;
|
||||
|
||||
/// System as consumed by foreign code
|
||||
pub trait SystemCard: Default + Send + Sync + 'static {
|
||||
@@ -83,7 +82,7 @@ impl<T: SystemCard> DynSystemCard for T {
|
||||
|
||||
/// System as defined by author
|
||||
pub trait System: Send + Sync + SystemCard + 'static {
|
||||
fn env() -> Vec<(String, MemKind)>;
|
||||
fn env() -> Vec<GenItem>;
|
||||
fn vfs() -> DeclFs;
|
||||
fn lexers() -> Vec<LexerObj>;
|
||||
fn parsers() -> Vec<ParserObj>;
|
||||
@@ -91,7 +90,7 @@ pub trait System: Send + Sync + SystemCard + 'static {
|
||||
}
|
||||
|
||||
pub trait DynSystem: Send + Sync + DynSystemCard + 'static {
|
||||
fn dyn_env(&self) -> HashMap<String, MemKind>;
|
||||
fn dyn_env(&self) -> Vec<GenItem>;
|
||||
fn dyn_vfs(&self) -> DeclFs;
|
||||
fn dyn_lexers(&self) -> Vec<LexerObj>;
|
||||
fn dyn_parsers(&self) -> Vec<ParserObj>;
|
||||
@@ -100,7 +99,7 @@ pub trait DynSystem: Send + Sync + DynSystemCard + 'static {
|
||||
}
|
||||
|
||||
impl<T: System> DynSystem for T {
|
||||
fn dyn_env(&self) -> HashMap<String, MemKind> { Self::env().into_iter().collect() }
|
||||
fn dyn_env(&self) -> Vec<GenItem> { Self::env() }
|
||||
fn dyn_vfs(&self) -> DeclFs { Self::vfs() }
|
||||
fn dyn_lexers(&self) -> Vec<LexerObj> { Self::lexers() }
|
||||
fn dyn_parsers(&self) -> Vec<ParserObj> { Self::parsers() }
|
||||
@@ -112,10 +111,10 @@ impl<T: System> DynSystem for T {
|
||||
fn card(&self) -> &dyn DynSystemCard { self }
|
||||
}
|
||||
|
||||
pub async fn downcast_atom<A>(foreign: ForeignAtom<'_>) -> Result<TypAtom<'_, A>, ForeignAtom<'_>>
|
||||
pub async fn downcast_atom<A>(foreign: ForeignAtom) -> Result<TypAtom<A>, ForeignAtom>
|
||||
where A: AtomicFeatures {
|
||||
let mut data = &foreign.atom.data[..];
|
||||
let ctx = foreign.ctx.clone();
|
||||
let ctx = foreign.ctx().clone();
|
||||
let value = AtomTypeId::decode(Pin::new(&mut data)).await;
|
||||
let own_inst = ctx.get::<CtedObj>().inst();
|
||||
let owner = if *ctx.get::<api::SysId>() == foreign.atom.owner {
|
||||
|
||||
@@ -2,19 +2,16 @@ use crate::entrypoint::ExtensionData;
|
||||
|
||||
#[cfg(feature = "tokio")]
|
||||
pub async fn tokio_main(data: ExtensionData) {
|
||||
use std::future::Future;
|
||||
use std::io::Write;
|
||||
use std::mem;
|
||||
use std::pin::{Pin, pin};
|
||||
use std::pin::Pin;
|
||||
use std::rc::Rc;
|
||||
|
||||
use async_std::io;
|
||||
use async_stream::stream;
|
||||
use futures::StreamExt;
|
||||
use futures::future::LocalBoxFuture;
|
||||
use futures::stream::FuturesUnordered;
|
||||
use futures::{StreamExt, stream, stream_select};
|
||||
use orchid_api_traits::{Decode, Encode};
|
||||
use orchid_base::clone;
|
||||
use tokio::task::{LocalSet, spawn_local};
|
||||
|
||||
use crate::api;
|
||||
|
||||
@@ -1,34 +1,67 @@
|
||||
use std::num::NonZero;
|
||||
use std::ops::Range;
|
||||
use std::rc::Rc;
|
||||
|
||||
use dyn_clone::{DynClone, clone_box};
|
||||
use futures::FutureExt;
|
||||
use futures::future::{LocalBoxFuture, join_all};
|
||||
use hashbrown::HashMap;
|
||||
use hashbrown::{HashMap, HashSet};
|
||||
use itertools::Itertools;
|
||||
use orchid_base::interner::Tok;
|
||||
use orchid_base::interner::{Interner, Tok};
|
||||
use orchid_base::location::Pos;
|
||||
use orchid_base::name::Sym;
|
||||
use orchid_base::reqnot::ReqHandlish;
|
||||
use orchid_base::tree::{TokTree, Token};
|
||||
use ordered_float::NotNan;
|
||||
use orchid_base::tree::{TokTree, Token, TokenVariant};
|
||||
use substack::Substack;
|
||||
use trait_set::trait_set;
|
||||
|
||||
use crate::api;
|
||||
use crate::atom::{AtomFactory, ForeignAtom};
|
||||
use crate::conv::ToExpr;
|
||||
use crate::entrypoint::MemberRecord;
|
||||
use crate::expr::{Expr, ExprHandle};
|
||||
use crate::func_atom::{ExprFunc, Fun};
|
||||
use crate::gen_expr::{GExpr, arg, call, lambda, seq};
|
||||
use crate::macros::Rule;
|
||||
use crate::system::SysCtx;
|
||||
|
||||
pub type GenTokTree<'a> = TokTree<'a, ForeignAtom<'a>, AtomFactory>;
|
||||
pub type GenTok<'a> = Token<'a, ForeignAtom<'a>, AtomFactory>;
|
||||
pub type GenTokTree = TokTree<Expr, GExpr>;
|
||||
pub type GenTok = Token<Expr, GExpr>;
|
||||
|
||||
pub async fn do_extra(f: &AtomFactory, r: Range<u32>, ctx: SysCtx) -> api::TokenTree {
|
||||
api::TokenTree { range: r, token: api::Token::Atom(f.clone().build(ctx).await) }
|
||||
impl TokenVariant<api::Expression> for GExpr {
|
||||
type FromApiCtx<'a> = ();
|
||||
type ToApiCtx<'a> = (SysCtx, &'a dyn ReqHandlish);
|
||||
async fn from_api(
|
||||
_: &api::Expression,
|
||||
_: &mut Self::FromApiCtx<'_>,
|
||||
_: Pos,
|
||||
_: &Interner,
|
||||
) -> Self {
|
||||
panic!("Received new expression from host")
|
||||
}
|
||||
async fn into_api(self, (ctx, hand): &mut Self::ToApiCtx<'_>) -> api::Expression {
|
||||
self.api_return(ctx.clone(), hand).await
|
||||
}
|
||||
}
|
||||
|
||||
impl TokenVariant<api::ExprTicket> for Expr {
|
||||
type FromApiCtx<'a> = SysCtx;
|
||||
async fn from_api(
|
||||
api: &api::ExprTicket,
|
||||
ctx: &mut Self::FromApiCtx<'_>,
|
||||
_: Pos,
|
||||
_: &Interner,
|
||||
) -> Self {
|
||||
// SAFETY: receiving trees from sublexers implies ownership transfer
|
||||
Expr::from_handle(Rc::new(unsafe { ExprHandle::from_args(ctx.clone(), *api) }))
|
||||
}
|
||||
type ToApiCtx<'a> = ();
|
||||
async fn into_api(self, (): &mut Self::ToApiCtx<'_>) -> api::ExprTicket {
|
||||
let hand = self.handle();
|
||||
std::mem::drop(self);
|
||||
let h = match Rc::try_unwrap(hand) {
|
||||
Ok(h) => h,
|
||||
Err(h) => h.as_ref().clone().await,
|
||||
};
|
||||
h.into_tk()
|
||||
}
|
||||
}
|
||||
|
||||
fn with_export(mem: GenMember, public: bool) -> Vec<GenItem> {
|
||||
@@ -47,14 +80,9 @@ impl GenItem {
|
||||
let kind = match self.kind {
|
||||
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) => {
|
||||
let mut rules = Vec::with_capacity(gen_rules.len());
|
||||
for rule in gen_rules {
|
||||
rules.push(rule.into_api(ctx).await)
|
||||
}
|
||||
api::ItemKind::Macro(api::MacroBlock { priority, rules })
|
||||
},
|
||||
GenItemKind::Import(cn) => api::ItemKind::Import(
|
||||
Sym::parse(&cn, ctx.sys().i()).await.expect("Import path empty string").to_api(),
|
||||
),
|
||||
};
|
||||
let comments = join_all(self.comments.iter().map(|c| async {
|
||||
api::Comment {
|
||||
@@ -70,24 +98,23 @@ impl GenItem {
|
||||
pub fn cnst(public: bool, name: &str, value: impl ToExpr) -> Vec<GenItem> {
|
||||
with_export(GenMember { name: name.to_string(), kind: MemKind::Const(value.to_expr()) }, public)
|
||||
}
|
||||
pub fn import(public: bool, path: &str) -> Vec<GenItem> {
|
||||
let mut out = vec![GenItemKind::Import(path.to_string())];
|
||||
if public {
|
||||
out.push(GenItemKind::Export(path.split("::").last().unwrap().to_string()));
|
||||
}
|
||||
out.into_iter().map(|kind| GenItem { comments: vec![], kind }).collect()
|
||||
}
|
||||
pub fn module(
|
||||
public: bool,
|
||||
name: &str,
|
||||
imports: impl IntoIterator<Item = Sym>,
|
||||
items: impl IntoIterator<Item = Vec<GenItem>>,
|
||||
) -> Vec<GenItem> {
|
||||
let (name, kind) = root_mod(name, imports, items);
|
||||
let (name, kind) = root_mod(name, items);
|
||||
with_export(GenMember { name, kind }, public)
|
||||
}
|
||||
pub fn root_mod(
|
||||
name: &str,
|
||||
imports: impl IntoIterator<Item = Sym>,
|
||||
items: impl IntoIterator<Item = Vec<GenItem>>,
|
||||
) -> (String, MemKind) {
|
||||
let kind = MemKind::Mod {
|
||||
imports: imports.into_iter().collect(),
|
||||
items: items.into_iter().flatten().collect(),
|
||||
};
|
||||
pub fn root_mod(name: &str, items: impl IntoIterator<Item = Vec<GenItem>>) -> (String, MemKind) {
|
||||
let kind = MemKind::Mod { items: items.into_iter().flatten().collect() };
|
||||
(name.to_string(), kind)
|
||||
}
|
||||
pub fn fun<I, O>(exported: bool, name: &str, xf: impl ExprFunc<I, O>) -> Vec<GenItem> {
|
||||
@@ -107,12 +134,12 @@ pub fn fun<I, O>(exported: bool, name: &str, xf: impl ExprFunc<I, O>) -> Vec<Gen
|
||||
});
|
||||
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> {
|
||||
let prio = prio.map(|p| NotNan::new(p).unwrap());
|
||||
vec![GenItem {
|
||||
kind: GenItemKind::Macro(prio, rules.into_iter().collect_vec()),
|
||||
comments: vec![],
|
||||
}]
|
||||
pub fn prefix(path: &str, items: impl IntoIterator<Item = Vec<GenItem>>) -> Vec<GenItem> {
|
||||
let mut items = items.into_iter().flatten().collect_vec();
|
||||
for step in path.split("::").collect_vec().into_iter().rev() {
|
||||
items = module(true, step, [items]);
|
||||
}
|
||||
items
|
||||
}
|
||||
|
||||
pub fn comments<'a>(
|
||||
@@ -126,6 +153,58 @@ pub fn comments<'a>(
|
||||
val
|
||||
}
|
||||
|
||||
/// Trivially merge a gen tree. Behaviours were chosen to make this simple.
|
||||
///
|
||||
/// - Comments on imports are discarded
|
||||
/// - Comments on exports and submodules are combined
|
||||
/// - Duplicate constants result in an error
|
||||
/// - A combination of lazy and anything results in an error
|
||||
pub fn merge_trivial(trees: impl IntoIterator<Item = Vec<GenItem>>) -> Vec<GenItem> {
|
||||
let mut imported = HashSet::<String>::new();
|
||||
let mut exported = HashMap::<String, HashSet<String>>::new();
|
||||
let mut members = HashMap::<String, (MemKind, HashSet<String>)>::new();
|
||||
for item in trees.into_iter().flatten() {
|
||||
match item.kind {
|
||||
GenItemKind::Import(sym) => {
|
||||
imported.insert(sym);
|
||||
},
|
||||
GenItemKind::Export(e) =>
|
||||
exported.entry(e.clone()).or_insert(HashSet::new()).extend(item.comments.iter().cloned()),
|
||||
GenItemKind::Member(mem) => match mem.kind {
|
||||
unit @ (MemKind::Const(_) | MemKind::Lazy(_)) => {
|
||||
let prev = members.insert(mem.name.clone(), (unit, item.comments.into_iter().collect()));
|
||||
assert!(prev.is_none(), "Conflict in trivial tree merge on {}", mem.name);
|
||||
},
|
||||
MemKind::Mod { items } => match members.entry(mem.name.clone()) {
|
||||
hashbrown::hash_map::Entry::Vacant(slot) => {
|
||||
slot.insert((MemKind::Mod { items }, item.comments.into_iter().collect()));
|
||||
},
|
||||
hashbrown::hash_map::Entry::Occupied(mut old) => match old.get_mut() {
|
||||
(MemKind::Mod { items: old_items }, old_cmts) => {
|
||||
let mut swap = vec![];
|
||||
std::mem::swap(&mut swap, old_items);
|
||||
*old_items = merge_trivial([swap, items]);
|
||||
old_cmts.extend(item.comments);
|
||||
},
|
||||
_ => panic!("Conflict in trivial merge on {}", mem.name),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
(imported.into_iter().map(|txt| GenItem { comments: vec![], kind: GenItemKind::Import(txt) }))
|
||||
.chain(exported.into_iter().map(|(k, cmtv)| GenItem {
|
||||
comments: cmtv.into_iter().collect(),
|
||||
kind: GenItemKind::Export(k),
|
||||
}))
|
||||
.chain(members.into_iter().map(|(name, (kind, cmtv))| GenItem {
|
||||
comments: cmtv.into_iter().collect(),
|
||||
kind: GenItemKind::Member(GenMember { name, kind }),
|
||||
}))
|
||||
.collect()
|
||||
}
|
||||
|
||||
trait_set! {
|
||||
trait LazyMemberCallback =
|
||||
FnOnce(Sym, SysCtx) -> LocalBoxFuture<'static, MemKind> + DynClone
|
||||
@@ -144,13 +223,12 @@ impl Clone for LazyMemberFactory {
|
||||
pub enum GenItemKind {
|
||||
Member(GenMember),
|
||||
Export(String),
|
||||
Import(Sym),
|
||||
Macro(Option<NotNan<f64>>, Vec<Rule>),
|
||||
Import(String),
|
||||
}
|
||||
|
||||
pub struct GenMember {
|
||||
name: String,
|
||||
kind: MemKind,
|
||||
pub name: String,
|
||||
pub kind: MemKind,
|
||||
}
|
||||
impl GenMember {
|
||||
pub async fn into_api(self, ctx: &mut impl TreeIntoApiCtx) -> api::Member {
|
||||
@@ -164,7 +242,7 @@ impl GenMember {
|
||||
|
||||
pub enum MemKind {
|
||||
Const(GExpr),
|
||||
Mod { imports: Vec<Sym>, items: Vec<GenItem> },
|
||||
Mod { items: Vec<GenItem> },
|
||||
Lazy(LazyMemberFactory),
|
||||
}
|
||||
impl MemKind {
|
||||
@@ -172,15 +250,12 @@ impl MemKind {
|
||||
match self {
|
||||
Self::Lazy(lazy) => api::MemberKind::Lazy(ctx.with_lazy(lazy)),
|
||||
Self::Const(c) => api::MemberKind::Const(c.api_return(ctx.sys(), ctx.req()).await),
|
||||
Self::Mod { imports, items } => {
|
||||
let all_items = (imports.into_iter())
|
||||
.map(|t| GenItem { comments: vec![], kind: GenItemKind::Import(t) })
|
||||
.chain(items);
|
||||
let mut items = Vec::new();
|
||||
for i in all_items {
|
||||
items.push(i.into_api(ctx).boxed_local().await)
|
||||
Self::Mod { items } => {
|
||||
let mut api_items = Vec::new();
|
||||
for i in items {
|
||||
api_items.push(i.into_api(ctx).boxed_local().await)
|
||||
}
|
||||
api::MemberKind::Module(api::Module { items })
|
||||
api::MemberKind::Module(api::Module { items: api_items })
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -189,7 +264,6 @@ impl MemKind {
|
||||
pub trait TreeIntoApiCtx {
|
||||
fn sys(&self) -> SysCtx;
|
||||
fn with_lazy(&mut self, fac: LazyMemberFactory) -> api::TreeId;
|
||||
fn with_rule(&mut self, rule: Rc<Rule>) -> api::MacroId;
|
||||
fn push_path(&mut self, seg: Tok<String>) -> impl TreeIntoApiCtx;
|
||||
fn req(&self) -> &impl ReqHandlish;
|
||||
}
|
||||
@@ -199,7 +273,6 @@ pub struct TreeIntoApiCtxImpl<'a, 'b, RH: ReqHandlish> {
|
||||
pub basepath: &'a [Tok<String>],
|
||||
pub path: Substack<'a, Tok<String>>,
|
||||
pub lazy_members: &'b mut HashMap<api::TreeId, MemberRecord>,
|
||||
pub rules: &'b mut HashMap<api::MacroId, Rc<Rule>>,
|
||||
pub req: &'a RH,
|
||||
}
|
||||
|
||||
@@ -209,7 +282,6 @@ impl<RH: ReqHandlish> TreeIntoApiCtx for TreeIntoApiCtxImpl<'_, '_, RH> {
|
||||
TreeIntoApiCtxImpl {
|
||||
req: self.req,
|
||||
lazy_members: self.lazy_members,
|
||||
rules: self.rules,
|
||||
sys: self.sys.clone(),
|
||||
basepath: self.basepath,
|
||||
path: self.path.push(seg),
|
||||
@@ -221,10 +293,5 @@ impl<RH: ReqHandlish> TreeIntoApiCtx for TreeIntoApiCtxImpl<'_, '_, RH> {
|
||||
self.lazy_members.insert(id, MemberRecord::Gen(path, fac));
|
||||
id
|
||||
}
|
||||
fn with_rule(&mut self, rule: Rc<Rule>) -> orchid_api::MacroId {
|
||||
let id = api::MacroId(NonZero::new((self.lazy_members.len() + 1) as u64).unwrap());
|
||||
self.rules.insert(id, rule);
|
||||
id
|
||||
}
|
||||
fn req(&self) -> &impl ReqHandlish { self.req }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user