Updated everything and moved to hard tab indentation

This commit is contained in:
2025-01-08 19:20:34 +01:00
parent 7cdfe7e3c4
commit 52c8d1c95a
100 changed files with 5949 additions and 5998 deletions

View File

@@ -1,13 +1,13 @@
use std::any::{type_name, Any, TypeId};
use std::any::{Any, TypeId, type_name};
use std::fmt;
use std::io::{Read, Write};
use std::marker::PhantomData;
use std::ops::Deref;
use std::sync::{Arc, OnceLock};
use dyn_clone::{clone_box, DynClone};
use orchid_api_traits::{enc_vec, Coding, Decode, Encode, Request};
use orchid_base::error::{mk_err, OrcErr, OrcRes};
use dyn_clone::{DynClone, clone_box};
use orchid_api_traits::{Coding, Decode, Encode, Request, enc_vec};
use orchid_base::error::{OrcErr, OrcRes, mk_err};
use orchid_base::intern;
use orchid_base::location::Pos;
use orchid_base::name::Sym;
@@ -18,241 +18,247 @@ use trait_set::trait_set;
use crate::api;
// use crate::error::{ProjectError, ProjectResult};
use crate::expr::{Expr, ExprData, ExprHandle, ExprKind};
use crate::system::{atom_info_for, downcast_atom, DynSystemCard, SysCtx};
use crate::system::{DynSystemCard, SysCtx, atom_info_for, downcast_atom};
pub trait AtomCard: 'static + Sized {
type Data: Clone + Coding + Sized;
type Data: Clone + Coding + Sized;
}
pub trait AtomicVariant {}
pub trait Atomic: 'static + Sized {
type Variant: AtomicVariant;
type Data: Clone + Coding + Sized;
fn reg_reqs() -> MethodSet<Self>;
type Variant: AtomicVariant;
type Data: Clone + Coding + Sized;
fn reg_reqs() -> MethodSet<Self>;
}
impl<A: Atomic> AtomCard for A {
type Data = <Self as Atomic>::Data;
type Data = <Self as Atomic>::Data;
}
pub trait AtomicFeatures: Atomic {
fn factory(self) -> AtomFactory;
type Info: AtomDynfo;
fn info() -> Self::Info;
fn dynfo() -> Box<dyn AtomDynfo>;
fn factory(self) -> AtomFactory;
type Info: AtomDynfo;
fn info() -> Self::Info;
fn dynfo() -> Box<dyn AtomDynfo>;
}
pub trait ToAtom {
fn to_atom_factory(self) -> AtomFactory;
fn to_atom_factory(self) -> AtomFactory;
}
impl<A: AtomicFeatures> ToAtom for A {
fn to_atom_factory(self) -> AtomFactory { self.factory() }
fn to_atom_factory(self) -> AtomFactory { self.factory() }
}
impl ToAtom for AtomFactory {
fn to_atom_factory(self) -> AtomFactory { self }
fn to_atom_factory(self) -> AtomFactory { self }
}
pub trait AtomicFeaturesImpl<Variant: AtomicVariant> {
fn _factory(self) -> AtomFactory;
type _Info: AtomDynfo;
fn _info() -> Self::_Info;
fn _factory(self) -> AtomFactory;
type _Info: AtomDynfo;
fn _info() -> Self::_Info;
}
impl<A: Atomic + AtomicFeaturesImpl<A::Variant>> AtomicFeatures for A {
fn factory(self) -> AtomFactory { self._factory() }
type Info = <Self as AtomicFeaturesImpl<A::Variant>>::_Info;
fn info() -> Self::Info { Self::_info() }
fn dynfo() -> Box<dyn AtomDynfo> { Box::new(Self::info()) }
fn factory(self) -> AtomFactory { self._factory() }
type Info = <Self as AtomicFeaturesImpl<A::Variant>>::_Info;
fn info() -> Self::Info { Self::_info() }
fn dynfo() -> Box<dyn AtomDynfo> { Box::new(Self::info()) }
}
pub fn get_info<A: AtomCard>(
sys: &(impl DynSystemCard + ?Sized),
sys: &(impl DynSystemCard + ?Sized),
) -> (api::AtomId, Box<dyn AtomDynfo>) {
atom_info_for(sys, TypeId::of::<A>()).unwrap_or_else(|| {
panic!("Atom {} not associated with system {}", type_name::<A>(), sys.name())
})
atom_info_for(sys, TypeId::of::<A>()).unwrap_or_else(|| {
panic!("Atom {} not associated with system {}", type_name::<A>(), sys.name())
})
}
#[derive(Clone)]
pub struct ForeignAtom<'a> {
pub expr: Option<Arc<ExprHandle>>,
pub _life: PhantomData<&'a ()>,
pub ctx: SysCtx,
pub atom: api::Atom,
pub pos: Pos,
pub expr: Option<Arc<ExprHandle>>,
pub _life: PhantomData<&'a ()>,
pub ctx: SysCtx,
pub atom: api::Atom,
pub pos: Pos,
}
impl ForeignAtom<'_> {
pub fn oex_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 { handle: Some(handle), val: OnceLock::from(data) })
}
pub fn oex_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 { handle: Some(handle), val: OnceLock::from(data) })
}
}
impl ForeignAtom<'static> {
pub fn oex(self) -> Expr { self.oex_opt().unwrap() }
pub(crate) fn new(handle: Arc<ExprHandle>, atom: api::Atom, pos: Pos) -> Self {
ForeignAtom { _life: PhantomData, atom, ctx: handle.ctx.clone(), expr: Some(handle), pos }
}
pub fn request<M: AtomMethod>(&self, m: M) -> Option<M::Response> {
let rep = self.ctx.reqnot.request(api::Fwd(
self.atom.clone(),
Sym::parse(M::NAME).unwrap().tok().to_api(),
enc_vec(&m)
))?;
Some(M::Response::decode(&mut &rep[..]))
}
pub fn oex(self) -> Expr { self.oex_opt().unwrap() }
pub(crate) fn new(handle: Arc<ExprHandle>, atom: api::Atom, pos: Pos) -> Self {
ForeignAtom { _life: PhantomData, atom, ctx: handle.ctx.clone(), expr: Some(handle), pos }
}
pub fn request<M: AtomMethod>(&self, m: M) -> Option<M::Response> {
let rep = self.ctx.reqnot.request(api::Fwd(
self.atom.clone(),
Sym::parse(M::NAME).unwrap().tok().to_api(),
enc_vec(&m),
))?;
Some(M::Response::decode(&mut &rep[..]))
}
}
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)
}
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}::{:?}", if self.expr.is_some() { "Clause" } else { "Tok" }, self.atom)
}
}
impl fmt::Debug for ForeignAtom<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "ForeignAtom({self})") }
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "ForeignAtom({self})") }
}
impl AtomRepr for ForeignAtom<'_> {
type Ctx = SysCtx;
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 }
}
fn to_api(&self) -> orchid_api::Atom { self.atom.clone() }
type Ctx = SysCtx;
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 }
}
fn to_api(&self) -> orchid_api::Atom { self.atom.clone() }
}
pub struct NotTypAtom(pub Pos, pub Expr, pub Box<dyn AtomDynfo>);
impl NotTypAtom {
pub fn mk_err(&self) -> OrcErr {
mk_err(
intern!(str: "Not the expected type"),
format!("This expression is not a {}", self.2.name()),
[self.0.clone().into()],
)
}
pub fn mk_err(&self) -> OrcErr {
mk_err(
intern!(str: "Not the expected type"),
format!("This expression is not a {}", self.2.name()),
[self.0.clone().into()],
)
}
}
pub trait AtomMethod: Request {
const NAME: &str;
const NAME: &str;
}
pub trait Supports<M: AtomMethod>: AtomCard {
fn handle(&self, ctx: SysCtx, req: M) -> <M as Request>::Response;
fn handle(&self, ctx: SysCtx, req: M) -> <M as Request>::Response;
}
trait_set! {
trait AtomReqCb<A> = Fn(&A, SysCtx, &mut dyn Read, &mut dyn Write) + Send + Sync
trait AtomReqCb<A> = Fn(&A, SysCtx, &mut dyn Read, &mut dyn Write) + Send + Sync
}
pub struct AtomReqHandler<A: AtomCard> {
key: Sym,
cb: Box<dyn AtomReqCb<A>>,
key: Sym,
cb: Box<dyn AtomReqCb<A>>,
}
pub struct MethodSet<A: AtomCard> {
handlers: Vec<AtomReqHandler<A>>,
handlers: Vec<AtomReqHandler<A>>,
}
impl<A: AtomCard> MethodSet<A> {
pub fn new() -> Self { Self{ handlers: vec![] } }
pub fn new() -> Self { Self { handlers: vec![] } }
pub fn handle<M: AtomMethod>(mut self) -> Self where A: Supports<M> {
self.handlers.push(AtomReqHandler {
key: Sym::parse(M::NAME).expect("AtomMethod::NAME cannoot be empty"),
cb: Box::new(move |
a: &A,
ctx: SysCtx,
req: &mut dyn Read,
rep: &mut dyn Write
| {
Supports::<M>::handle(a, ctx, M::decode(req)).encode(rep);
})
});
self
}
pub fn handle<M: AtomMethod>(mut self) -> Self
where A: Supports<M> {
self.handlers.push(AtomReqHandler {
key: Sym::parse(M::NAME).expect("AtomMethod::NAME cannoot be empty"),
cb: Box::new(move |a: &A, ctx: SysCtx, req: &mut dyn Read, rep: &mut dyn Write| {
Supports::<M>::handle(a, ctx, M::decode(req)).encode(rep);
}),
});
self
}
pub(crate) fn dispatch(
&self, atom: &A, ctx: SysCtx, key: Sym, req: &mut dyn Read, rep: &mut dyn Write
) -> bool {
match self.handlers.iter().find(|h| h.key == key) {
None => false,
Some(handler) => {
(handler.cb)(atom, ctx, req, rep);
true
},
}
}
pub(crate) fn dispatch(
&self,
atom: &A,
ctx: SysCtx,
key: Sym,
req: &mut dyn Read,
rep: &mut dyn Write,
) -> bool {
match self.handlers.iter().find(|h| h.key == key) {
None => false,
Some(handler) => {
(handler.cb)(atom, ctx, req, rep);
true
},
}
}
}
impl<A: AtomCard> Default for MethodSet<A> {
fn default() -> Self {
Self::new()
}
fn default() -> Self { Self::new() }
}
#[derive(Clone)]
pub struct TypAtom<'a, A: AtomicFeatures> {
pub data: ForeignAtom<'a>,
pub value: A::Data,
pub data: ForeignAtom<'a>,
pub value: A::Data,
}
impl<A: AtomicFeatures> TypAtom<'static, A> {
pub fn downcast(expr: Arc<ExprHandle>) -> Result<Self, NotTypAtom> {
match Expr::new(expr).foreign_atom() {
Err(oe) => Err(NotTypAtom(oe.get_data().pos.clone(), oe, Box::new(A::info()))),
Ok(atm) => match downcast_atom::<A>(atm) {
Err(fa) => Err(NotTypAtom(fa.pos.clone(), fa.oex(), Box::new(A::info()))),
Ok(tatom) => Ok(tatom),
},
}
}
pub fn downcast(expr: Arc<ExprHandle>) -> Result<Self, NotTypAtom> {
match Expr::new(expr).foreign_atom() {
Err(oe) => Err(NotTypAtom(oe.get_data().pos.clone(), oe, Box::new(A::info()))),
Ok(atm) => match downcast_atom::<A>(atm) {
Err(fa) => Err(NotTypAtom(fa.pos.clone(), fa.oex(), Box::new(A::info()))),
Ok(tatom) => Ok(tatom),
},
}
}
}
impl<A: AtomicFeatures> TypAtom<'_, A> {
pub fn request<M: AtomMethod>(&self, req: M) -> M::Response where A: Supports<M> {
M::Response::decode(
&mut &self.data.ctx.reqnot.request(api::Fwd(
self.data.atom.clone(),
Sym::parse(M::NAME).unwrap().tok().to_api(),
enc_vec(&req)
)).unwrap()[..]
)
}
pub fn request<M: AtomMethod>(&self, req: M) -> M::Response
where A: Supports<M> {
M::Response::decode(
&mut &self
.data
.ctx
.reqnot
.request(api::Fwd(
self.data.atom.clone(),
Sym::parse(M::NAME).unwrap().tok().to_api(),
enc_vec(&req),
))
.unwrap()[..],
)
}
}
impl<A: AtomicFeatures> Deref for TypAtom<'_, A> {
type Target = A::Data;
fn deref(&self) -> &Self::Target { &self.value }
type Target = A::Data;
fn deref(&self) -> &Self::Target { &self.value }
}
pub struct AtomCtx<'a>(pub &'a [u8], pub Option<api::AtomId>, pub SysCtx);
pub trait AtomDynfo: Send + Sync + 'static {
fn tid(&self) -> TypeId;
fn name(&self) -> &'static str;
fn decode(&self, ctx: AtomCtx<'_>) -> Box<dyn Any>;
fn call(&self, ctx: AtomCtx<'_>, arg: api::ExprTicket) -> Expr;
fn call_ref(&self, ctx: AtomCtx<'_>, arg: api::ExprTicket) -> Expr;
fn print(&self, ctx: AtomCtx<'_>) -> String;
fn handle_req(&self, ctx: AtomCtx<'_>, key: Sym, req: &mut dyn Read, rep: &mut dyn Write) -> bool;
fn command(&self, ctx: AtomCtx<'_>) -> OrcRes<Option<Expr>>;
fn serialize(&self, ctx: AtomCtx<'_>, write: &mut dyn Write) -> Option<Vec<api::ExprTicket>>;
fn deserialize(&self, ctx: SysCtx, data: &[u8], refs: &[api::ExprTicket]) -> api::Atom;
fn drop(&self, ctx: AtomCtx<'_>);
fn tid(&self) -> TypeId;
fn name(&self) -> &'static str;
fn decode(&self, ctx: AtomCtx<'_>) -> Box<dyn Any>;
fn call(&self, ctx: AtomCtx<'_>, arg: api::ExprTicket) -> Expr;
fn call_ref(&self, ctx: AtomCtx<'_>, arg: api::ExprTicket) -> Expr;
fn print(&self, ctx: AtomCtx<'_>) -> String;
fn handle_req(&self, ctx: AtomCtx<'_>, key: Sym, req: &mut dyn Read, rep: &mut dyn Write)
-> bool;
fn command(&self, ctx: AtomCtx<'_>) -> OrcRes<Option<Expr>>;
fn serialize(&self, ctx: AtomCtx<'_>, write: &mut dyn Write) -> Option<Vec<api::ExprTicket>>;
fn deserialize(&self, ctx: SysCtx, data: &[u8], refs: &[api::ExprTicket]) -> api::Atom;
fn drop(&self, ctx: AtomCtx<'_>);
}
trait_set! {
pub trait AtomFactoryFn = FnOnce(SysCtx) -> api::Atom + DynClone + Send + Sync;
pub trait AtomFactoryFn = FnOnce(SysCtx) -> api::Atom + DynClone + Send + Sync;
}
pub struct AtomFactory(Box<dyn AtomFactoryFn>);
impl AtomFactory {
pub fn new(f: impl FnOnce(SysCtx) -> api::Atom + Clone + Send + Sync + 'static) -> Self {
Self(Box::new(f))
}
pub fn build(self, ctx: SysCtx) -> api::Atom { (self.0)(ctx) }
pub fn new(f: impl FnOnce(SysCtx) -> api::Atom + Clone + Send + Sync + 'static) -> Self {
Self(Box::new(f))
}
pub fn build(self, ctx: SysCtx) -> api::Atom { (self.0)(ctx) }
}
impl Clone for AtomFactory {
fn clone(&self) -> Self { AtomFactory(clone_box(&*self.0)) }
fn clone(&self) -> Self { AtomFactory(clone_box(&*self.0)) }
}
impl fmt::Debug for AtomFactory {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "AtomFactory") }
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "AtomFactory") }
}
impl fmt::Display for AtomFactory {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "AtomFactory") }
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "AtomFactory") }
}
pub fn err_not_callable() -> OrcErr {
mk_err(intern!(str: "This atom is not callable"), "Attempted to apply value as function", [])
mk_err(intern!(str: "This atom is not callable"), "Attempted to apply value as function", [])
}
pub fn err_not_command() -> OrcErr {
mk_err(intern!(str: "This atom is not a command"), "Settled on an inactionable value", [])
mk_err(intern!(str: "This atom is not a command"), "Settled on an inactionable value", [])
}

View File

@@ -12,8 +12,8 @@ use orchid_base::name::Sym;
use crate::api;
use crate::atom::{
AtomCard, AtomCtx, AtomDynfo, AtomFactory, Atomic, AtomicFeaturesImpl, AtomicVariant, MethodSet,
err_not_callable, err_not_command, get_info,
AtomCard, AtomCtx, AtomDynfo, AtomFactory, Atomic, AtomicFeaturesImpl, AtomicVariant, MethodSet,
err_not_callable, err_not_command, get_info,
};
use crate::expr::{Expr, ExprHandle, bot};
use crate::system::SysCtx;
@@ -21,197 +21,197 @@ use crate::system::SysCtx;
pub struct OwnedVariant;
impl AtomicVariant for OwnedVariant {}
impl<A: OwnedAtom + Atomic<Variant = OwnedVariant>> AtomicFeaturesImpl<OwnedVariant> for A {
fn _factory(self) -> AtomFactory {
AtomFactory::new(move |ctx| {
let rec = OBJ_STORE.add(Box::new(self));
let (id, _) = get_info::<A>(ctx.cted.inst().card());
let mut data = enc_vec(&id);
rec.encode(&mut data);
api::Atom { drop: Some(api::AtomId(rec.id())), data, owner: ctx.id }
})
}
fn _info() -> Self::_Info { OwnedAtomDynfo(A::reg_reqs()) }
type _Info = OwnedAtomDynfo<A>;
fn _factory(self) -> AtomFactory {
AtomFactory::new(move |ctx| {
let rec = OBJ_STORE.add(Box::new(self));
let (id, _) = get_info::<A>(ctx.cted.inst().card());
let mut data = enc_vec(&id);
rec.encode(&mut data);
api::Atom { drop: Some(api::AtomId(rec.id())), data, owner: ctx.id }
})
}
fn _info() -> Self::_Info { OwnedAtomDynfo(A::reg_reqs()) }
type _Info = OwnedAtomDynfo<A>;
}
fn with_atom<U>(id: api::AtomId, f: impl FnOnce(IdRecord<'_, Box<dyn DynOwnedAtom>>) -> U) -> U {
f(OBJ_STORE.get(id.0).unwrap_or_else(|| panic!("Received invalid atom ID: {}", id.0)))
f(OBJ_STORE.get(id.0).unwrap_or_else(|| panic!("Received invalid atom ID: {}", id.0)))
}
pub struct OwnedAtomDynfo<T: OwnedAtom>(MethodSet<T>);
impl<T: OwnedAtom> AtomDynfo for OwnedAtomDynfo<T> {
fn print(&self, AtomCtx(_, id, ctx): AtomCtx<'_>) -> String {
with_atom(id.unwrap(), |a| a.dyn_print(ctx))
}
fn tid(&self) -> TypeId { TypeId::of::<T>() }
fn name(&self) -> &'static str { type_name::<T>() }
fn decode(&self, AtomCtx(data, ..): AtomCtx) -> Box<dyn Any> {
Box::new(<T as AtomCard>::Data::decode(&mut &data[..]))
}
fn call(&self, AtomCtx(_, id, ctx): AtomCtx, arg: api::ExprTicket) -> Expr {
with_atom(id.unwrap(), |a| a.remove().dyn_call(ctx, arg))
}
fn call_ref(&self, AtomCtx(_, id, ctx): AtomCtx, arg: api::ExprTicket) -> Expr {
with_atom(id.unwrap(), |a| a.dyn_call_ref(ctx, arg))
}
fn handle_req(
&self,
AtomCtx(_, id, ctx): AtomCtx,
key: Sym,
req: &mut dyn Read,
rep: &mut dyn Write,
) -> bool {
with_atom(id.unwrap(), |a| {
self.0.dispatch(a.as_any_ref().downcast_ref().unwrap(), ctx, key, req, rep)
})
}
fn command(&self, AtomCtx(_, id, ctx): AtomCtx<'_>) -> OrcRes<Option<Expr>> {
with_atom(id.unwrap(), |a| a.remove().dyn_command(ctx))
}
fn drop(&self, AtomCtx(_, id, ctx): AtomCtx) {
with_atom(id.unwrap(), |a| a.remove().dyn_free(ctx))
}
fn serialize(
&self,
AtomCtx(_, id, ctx): AtomCtx<'_>,
write: &mut dyn Write,
) -> Option<Vec<api::ExprTicket>> {
let id = id.unwrap();
id.encode(write);
with_atom(id, |a| a.dyn_serialize(ctx, write))
.map(|v| v.into_iter().map(|t| t.handle.unwrap().tk).collect_vec())
}
fn deserialize(&self, ctx: SysCtx, data: &[u8], refs: &[api::ExprTicket]) -> orchid_api::Atom {
let refs = refs.iter().map(|tk| Expr::new(Arc::new(ExprHandle::from_args(ctx.clone(), *tk))));
let obj = T::deserialize(DeserCtxImpl(data, &ctx), T::Refs::from_iter(refs));
obj._factory().build(ctx)
}
fn print(&self, AtomCtx(_, id, ctx): AtomCtx<'_>) -> String {
with_atom(id.unwrap(), |a| a.dyn_print(ctx))
}
fn tid(&self) -> TypeId { TypeId::of::<T>() }
fn name(&self) -> &'static str { type_name::<T>() }
fn decode(&self, AtomCtx(data, ..): AtomCtx) -> Box<dyn Any> {
Box::new(<T as AtomCard>::Data::decode(&mut &data[..]))
}
fn call(&self, AtomCtx(_, id, ctx): AtomCtx, arg: api::ExprTicket) -> Expr {
with_atom(id.unwrap(), |a| a.remove().dyn_call(ctx, arg))
}
fn call_ref(&self, AtomCtx(_, id, ctx): AtomCtx, arg: api::ExprTicket) -> Expr {
with_atom(id.unwrap(), |a| a.dyn_call_ref(ctx, arg))
}
fn handle_req(
&self,
AtomCtx(_, id, ctx): AtomCtx,
key: Sym,
req: &mut dyn Read,
rep: &mut dyn Write,
) -> bool {
with_atom(id.unwrap(), |a| {
self.0.dispatch(a.as_any_ref().downcast_ref().unwrap(), ctx, key, req, rep)
})
}
fn command(&self, AtomCtx(_, id, ctx): AtomCtx<'_>) -> OrcRes<Option<Expr>> {
with_atom(id.unwrap(), |a| a.remove().dyn_command(ctx))
}
fn drop(&self, AtomCtx(_, id, ctx): AtomCtx) {
with_atom(id.unwrap(), |a| a.remove().dyn_free(ctx))
}
fn serialize(
&self,
AtomCtx(_, id, ctx): AtomCtx<'_>,
write: &mut dyn Write,
) -> Option<Vec<api::ExprTicket>> {
let id = id.unwrap();
id.encode(write);
with_atom(id, |a| a.dyn_serialize(ctx, write))
.map(|v| v.into_iter().map(|t| t.handle.unwrap().tk).collect_vec())
}
fn deserialize(&self, ctx: SysCtx, data: &[u8], refs: &[api::ExprTicket]) -> orchid_api::Atom {
let refs = refs.iter().map(|tk| Expr::new(Arc::new(ExprHandle::from_args(ctx.clone(), *tk))));
let obj = T::deserialize(DeserCtxImpl(data, &ctx), T::Refs::from_iter(refs));
obj._factory().build(ctx)
}
}
pub trait DeserializeCtx: Sized {
fn read<T: Decode>(&mut self) -> T;
fn is_empty(&self) -> bool;
fn assert_empty(self) { assert!(self.is_empty(), "Bytes found after decoding") }
fn decode<T: Decode>(mut self) -> T {
let t = self.read();
self.assert_empty();
t
}
fn sys(&self) -> SysCtx;
fn read<T: Decode>(&mut self) -> T;
fn is_empty(&self) -> bool;
fn assert_empty(self) { assert!(self.is_empty(), "Bytes found after decoding") }
fn decode<T: Decode>(mut self) -> T {
let t = self.read();
self.assert_empty();
t
}
fn sys(&self) -> SysCtx;
}
struct DeserCtxImpl<'a>(&'a [u8], &'a SysCtx);
impl DeserializeCtx for DeserCtxImpl<'_> {
fn read<T: Decode>(&mut self) -> T { T::decode(&mut self.0) }
fn is_empty(&self) -> bool { self.0.is_empty() }
fn sys(&self) -> SysCtx { self.1.clone() }
fn read<T: Decode>(&mut self) -> T { T::decode(&mut self.0) }
fn is_empty(&self) -> bool { self.0.is_empty() }
fn sys(&self) -> SysCtx { self.1.clone() }
}
pub trait RefSet {
fn from_iter<I: Iterator<Item = Expr> + ExactSizeIterator>(refs: I) -> Self;
fn to_vec(self) -> Vec<Expr>;
fn from_iter<I: Iterator<Item = Expr> + ExactSizeIterator>(refs: I) -> Self;
fn to_vec(self) -> Vec<Expr>;
}
static E_NON_SER: &str = "Never is a stand-in refset for non-serializable atoms";
impl RefSet for Never {
fn from_iter<I>(_: I) -> Self { panic!("{E_NON_SER}") }
fn to_vec(self) -> Vec<Expr> { panic!("{E_NON_SER}") }
fn from_iter<I>(_: I) -> Self { panic!("{E_NON_SER}") }
fn to_vec(self) -> Vec<Expr> { panic!("{E_NON_SER}") }
}
impl RefSet for () {
fn to_vec(self) -> Vec<Expr> { Vec::new() }
fn from_iter<I: Iterator<Item = Expr> + ExactSizeIterator>(refs: I) -> Self {
assert_eq!(refs.len(), 0, "Expected no refs")
}
fn to_vec(self) -> Vec<Expr> { Vec::new() }
fn from_iter<I: Iterator<Item = Expr> + ExactSizeIterator>(refs: I) -> Self {
assert_eq!(refs.len(), 0, "Expected no refs")
}
}
impl RefSet for Vec<Expr> {
fn from_iter<I: Iterator<Item = Expr> + ExactSizeIterator>(refs: I) -> Self { refs.collect_vec() }
fn to_vec(self) -> Vec<Expr> { self }
fn from_iter<I: Iterator<Item = Expr> + ExactSizeIterator>(refs: I) -> Self { refs.collect_vec() }
fn to_vec(self) -> Vec<Expr> { self }
}
impl<const N: usize> RefSet for [Expr; N] {
fn to_vec(self) -> Vec<Expr> { self.into_iter().collect_vec() }
fn from_iter<I: Iterator<Item = Expr> + ExactSizeIterator>(refs: I) -> Self {
assert_eq!(refs.len(), N, "Wrong number of refs provided");
refs.collect_vec().try_into().unwrap_or_else(|_: Vec<_>| unreachable!())
}
fn to_vec(self) -> Vec<Expr> { self.into_iter().collect_vec() }
fn from_iter<I: Iterator<Item = Expr> + ExactSizeIterator>(refs: I) -> Self {
assert_eq!(refs.len(), N, "Wrong number of refs provided");
refs.collect_vec().try_into().unwrap_or_else(|_: Vec<_>| unreachable!())
}
}
/// Atoms that have a [Drop]
pub trait OwnedAtom: Atomic<Variant = OwnedVariant> + Send + Sync + Any + Clone + 'static {
/// If serializable, the collection that best stores subexpression references
/// for this atom.
///
/// - `()` for no subexppressions,
/// - `[Expr; N]` for a static number of subexpressions
/// - `Vec<Expr>` for a variable number of subexpressions
/// - `Never` if not serializable
///
/// If this isn't `Never`, you must override the default, panicking
/// `serialize` and `deserialize` implementation
type Refs: RefSet;
fn val(&self) -> Cow<'_, Self::Data>;
#[allow(unused_variables)]
fn call_ref(&self, arg: ExprHandle) -> Expr { bot([err_not_callable()]) }
fn call(self, arg: ExprHandle) -> Expr {
let ctx = arg.get_ctx();
let gcl = self.call_ref(arg);
self.free(ctx);
gcl
}
#[allow(unused_variables)]
fn command(self, ctx: SysCtx) -> OrcRes<Option<Expr>> { Err(err_not_command().into()) }
#[allow(unused_variables)]
fn free(self, ctx: SysCtx) {}
#[allow(unused_variables)]
fn print(&self, ctx: SysCtx) -> String { format!("OwnedAtom({})", type_name::<Self>()) }
#[allow(unused_variables)]
fn serialize(&self, ctx: SysCtx, write: &mut (impl Write + ?Sized)) -> Self::Refs {
assert!(
TypeId::of::<Self::Refs>() != TypeId::of::<Never>(),
"The extension scaffold is broken, this function should never be called on Never Refs"
);
panic!("Either implement serialize or set Refs to Never for {}", type_name::<Self>())
}
#[allow(unused_variables)]
fn deserialize(ctx: impl DeserializeCtx, refs: Self::Refs) -> Self {
assert!(
TypeId::of::<Self::Refs>() != TypeId::of::<Never>(),
"The extension scaffold is broken, this function should never be called on Never Refs"
);
panic!("Either implement deserialize or set Refs to Never for {}", type_name::<Self>())
}
/// If serializable, the collection that best stores subexpression references
/// for this atom.
///
/// - `()` for no subexppressions,
/// - `[Expr; N]` for a static number of subexpressions
/// - `Vec<Expr>` for a variable number of subexpressions
/// - `Never` if not serializable
///
/// If this isn't `Never`, you must override the default, panicking
/// `serialize` and `deserialize` implementation
type Refs: RefSet;
fn val(&self) -> Cow<'_, Self::Data>;
#[allow(unused_variables)]
fn call_ref(&self, arg: ExprHandle) -> Expr { bot([err_not_callable()]) }
fn call(self, arg: ExprHandle) -> Expr {
let ctx = arg.get_ctx();
let gcl = self.call_ref(arg);
self.free(ctx);
gcl
}
#[allow(unused_variables)]
fn command(self, ctx: SysCtx) -> OrcRes<Option<Expr>> { Err(err_not_command().into()) }
#[allow(unused_variables)]
fn free(self, ctx: SysCtx) {}
#[allow(unused_variables)]
fn print(&self, ctx: SysCtx) -> String { format!("OwnedAtom({})", type_name::<Self>()) }
#[allow(unused_variables)]
fn serialize(&self, ctx: SysCtx, write: &mut (impl Write + ?Sized)) -> Self::Refs {
assert!(
TypeId::of::<Self::Refs>() != TypeId::of::<Never>(),
"The extension scaffold is broken, this function should never be called on Never Refs"
);
panic!("Either implement serialize or set Refs to Never for {}", type_name::<Self>())
}
#[allow(unused_variables)]
fn deserialize(ctx: impl DeserializeCtx, refs: Self::Refs) -> Self {
assert!(
TypeId::of::<Self::Refs>() != TypeId::of::<Never>(),
"The extension scaffold is broken, this function should never be called on Never Refs"
);
panic!("Either implement deserialize or set Refs to Never for {}", type_name::<Self>())
}
}
pub trait DynOwnedAtom: Send + Sync + 'static {
fn atom_tid(&self) -> TypeId;
fn as_any_ref(&self) -> &dyn Any;
fn encode(&self, buffer: &mut dyn Write);
fn dyn_call_ref(&self, ctx: SysCtx, arg: api::ExprTicket) -> Expr;
fn dyn_call(self: Box<Self>, ctx: SysCtx, arg: api::ExprTicket) -> Expr;
fn dyn_command(self: Box<Self>, ctx: SysCtx) -> OrcRes<Option<Expr>>;
fn dyn_free(self: Box<Self>, ctx: SysCtx);
fn dyn_print(&self, ctx: SysCtx) -> String;
fn dyn_serialize(&self, ctx: SysCtx, sink: &mut dyn Write) -> Option<Vec<Expr>>;
fn atom_tid(&self) -> TypeId;
fn as_any_ref(&self) -> &dyn Any;
fn encode(&self, buffer: &mut dyn Write);
fn dyn_call_ref(&self, ctx: SysCtx, arg: api::ExprTicket) -> Expr;
fn dyn_call(self: Box<Self>, ctx: SysCtx, arg: api::ExprTicket) -> Expr;
fn dyn_command(self: Box<Self>, ctx: SysCtx) -> OrcRes<Option<Expr>>;
fn dyn_free(self: Box<Self>, ctx: SysCtx);
fn dyn_print(&self, ctx: SysCtx) -> String;
fn dyn_serialize(&self, ctx: SysCtx, sink: &mut dyn Write) -> Option<Vec<Expr>>;
}
impl<T: OwnedAtom> DynOwnedAtom for T {
fn atom_tid(&self) -> TypeId { TypeId::of::<T>() }
fn as_any_ref(&self) -> &dyn Any { self }
fn encode(&self, buffer: &mut dyn Write) { self.val().as_ref().encode(buffer) }
fn dyn_call_ref(&self, ctx: SysCtx, arg: api::ExprTicket) -> Expr {
self.call_ref(ExprHandle::from_args(ctx, arg))
}
fn dyn_call(self: Box<Self>, ctx: SysCtx, arg: api::ExprTicket) -> Expr {
self.call(ExprHandle::from_args(ctx, arg))
}
fn dyn_command(self: Box<Self>, ctx: SysCtx) -> OrcRes<Option<Expr>> { self.command(ctx) }
fn dyn_free(self: Box<Self>, ctx: SysCtx) { self.free(ctx) }
fn dyn_print(&self, ctx: SysCtx) -> String { self.print(ctx) }
fn dyn_serialize(&self, ctx: SysCtx, sink: &mut dyn Write) -> Option<Vec<Expr>> {
(TypeId::of::<Never>() != TypeId::of::<<Self as OwnedAtom>::Refs>())
.then(|| self.serialize(ctx, sink).to_vec())
}
fn atom_tid(&self) -> TypeId { TypeId::of::<T>() }
fn as_any_ref(&self) -> &dyn Any { self }
fn encode(&self, buffer: &mut dyn Write) { self.val().as_ref().encode(buffer) }
fn dyn_call_ref(&self, ctx: SysCtx, arg: api::ExprTicket) -> Expr {
self.call_ref(ExprHandle::from_args(ctx, arg))
}
fn dyn_call(self: Box<Self>, ctx: SysCtx, arg: api::ExprTicket) -> Expr {
self.call(ExprHandle::from_args(ctx, arg))
}
fn dyn_command(self: Box<Self>, ctx: SysCtx) -> OrcRes<Option<Expr>> { self.command(ctx) }
fn dyn_free(self: Box<Self>, ctx: SysCtx) { self.free(ctx) }
fn dyn_print(&self, ctx: SysCtx) -> String { self.print(ctx) }
fn dyn_serialize(&self, ctx: SysCtx, sink: &mut dyn Write) -> Option<Vec<Expr>> {
(TypeId::of::<Never>() != TypeId::of::<<Self as OwnedAtom>::Refs>())
.then(|| self.serialize(ctx, sink).to_vec())
}
}
pub(crate) static OBJ_STORE: IdStore<Box<dyn DynOwnedAtom>> = IdStore::new();

View File

@@ -7,8 +7,8 @@ use orchid_base::name::Sym;
use crate::api;
use crate::atom::{
AtomCard, AtomCtx, AtomDynfo, AtomFactory, Atomic, AtomicFeaturesImpl, AtomicVariant, MethodSet,
err_not_callable, err_not_command, get_info,
AtomCard, AtomCtx, AtomDynfo, AtomFactory, Atomic, AtomicFeaturesImpl, AtomicVariant, MethodSet,
err_not_callable, err_not_command, get_info,
};
use crate::expr::{Expr, ExprHandle, bot};
use crate::system::SysCtx;
@@ -16,65 +16,65 @@ use crate::system::SysCtx;
pub struct ThinVariant;
impl AtomicVariant for ThinVariant {}
impl<A: ThinAtom + Atomic<Variant = ThinVariant>> AtomicFeaturesImpl<ThinVariant> for A {
fn _factory(self) -> AtomFactory {
AtomFactory::new(move |ctx| {
let (id, _) = get_info::<A>(ctx.cted.inst().card());
let mut buf = enc_vec(&id);
self.encode(&mut buf);
api::Atom { drop: None, data: buf, owner: ctx.id }
})
}
fn _info() -> Self::_Info { ThinAtomDynfo(Self::reg_reqs()) }
type _Info = ThinAtomDynfo<Self>;
fn _factory(self) -> AtomFactory {
AtomFactory::new(move |ctx| {
let (id, _) = get_info::<A>(ctx.cted.inst().card());
let mut buf = enc_vec(&id);
self.encode(&mut buf);
api::Atom { drop: None, data: buf, owner: ctx.id }
})
}
fn _info() -> Self::_Info { ThinAtomDynfo(Self::reg_reqs()) }
type _Info = ThinAtomDynfo<Self>;
}
pub struct ThinAtomDynfo<T: ThinAtom>(MethodSet<T>);
impl<T: ThinAtom> AtomDynfo for ThinAtomDynfo<T> {
fn print(&self, AtomCtx(buf, _, ctx): AtomCtx<'_>) -> String {
T::decode(&mut &buf[..]).print(ctx)
}
fn tid(&self) -> TypeId { TypeId::of::<T>() }
fn name(&self) -> &'static str { type_name::<T>() }
fn decode(&self, AtomCtx(buf, ..): AtomCtx) -> Box<dyn Any> { Box::new(T::decode(&mut &buf[..])) }
fn call(&self, AtomCtx(buf, _, ctx): AtomCtx, arg: api::ExprTicket) -> Expr {
T::decode(&mut &buf[..]).call(ExprHandle::from_args(ctx, arg))
}
fn call_ref(&self, AtomCtx(buf, _, ctx): AtomCtx, arg: api::ExprTicket) -> Expr {
T::decode(&mut &buf[..]).call(ExprHandle::from_args(ctx, arg))
}
fn handle_req(
&self,
AtomCtx(buf, _, sys): AtomCtx,
key: Sym,
req: &mut dyn std::io::Read,
rep: &mut dyn Write,
) -> bool {
self.0.dispatch(&T::decode(&mut &buf[..]), sys, key, req, rep)
}
fn command(&self, AtomCtx(buf, _, ctx): AtomCtx<'_>) -> OrcRes<Option<Expr>> {
T::decode(&mut &buf[..]).command(ctx)
}
fn serialize(&self, actx: AtomCtx<'_>, write: &mut dyn Write) -> Option<Vec<api::ExprTicket>> {
T::decode(&mut &actx.0[..]).encode(write);
Some(Vec::new())
}
fn deserialize(&self, ctx: SysCtx, data: &[u8], refs: &[api::ExprTicket]) -> api::Atom {
assert!(refs.is_empty(), "Refs found when deserializing thin atom");
T::decode(&mut &data[..])._factory().build(ctx)
}
fn drop(&self, AtomCtx(buf, _, ctx): AtomCtx) {
let string_self = T::decode(&mut &buf[..]).print(ctx.clone());
writeln!(ctx.logger, "Received drop signal for non-drop atom {string_self:?}");
}
fn print(&self, AtomCtx(buf, _, ctx): AtomCtx<'_>) -> String {
T::decode(&mut &buf[..]).print(ctx)
}
fn tid(&self) -> TypeId { TypeId::of::<T>() }
fn name(&self) -> &'static str { type_name::<T>() }
fn decode(&self, AtomCtx(buf, ..): AtomCtx) -> Box<dyn Any> { Box::new(T::decode(&mut &buf[..])) }
fn call(&self, AtomCtx(buf, _, ctx): AtomCtx, arg: api::ExprTicket) -> Expr {
T::decode(&mut &buf[..]).call(ExprHandle::from_args(ctx, arg))
}
fn call_ref(&self, AtomCtx(buf, _, ctx): AtomCtx, arg: api::ExprTicket) -> Expr {
T::decode(&mut &buf[..]).call(ExprHandle::from_args(ctx, arg))
}
fn handle_req(
&self,
AtomCtx(buf, _, sys): AtomCtx,
key: Sym,
req: &mut dyn std::io::Read,
rep: &mut dyn Write,
) -> bool {
self.0.dispatch(&T::decode(&mut &buf[..]), sys, key, req, rep)
}
fn command(&self, AtomCtx(buf, _, ctx): AtomCtx<'_>) -> OrcRes<Option<Expr>> {
T::decode(&mut &buf[..]).command(ctx)
}
fn serialize(&self, actx: AtomCtx<'_>, write: &mut dyn Write) -> Option<Vec<api::ExprTicket>> {
T::decode(&mut &actx.0[..]).encode(write);
Some(Vec::new())
}
fn deserialize(&self, ctx: SysCtx, data: &[u8], refs: &[api::ExprTicket]) -> api::Atom {
assert!(refs.is_empty(), "Refs found when deserializing thin atom");
T::decode(&mut &data[..])._factory().build(ctx)
}
fn drop(&self, AtomCtx(buf, _, ctx): AtomCtx) {
let string_self = T::decode(&mut &buf[..]).print(ctx.clone());
writeln!(ctx.logger, "Received drop signal for non-drop atom {string_self:?}");
}
}
pub trait ThinAtom:
AtomCard<Data = Self> + Atomic<Variant = ThinVariant> + Coding + Send + Sync + 'static
AtomCard<Data = Self> + Atomic<Variant = ThinVariant> + Coding + Send + Sync + 'static
{
#[allow(unused_variables)]
fn call(&self, arg: ExprHandle) -> Expr { bot([err_not_callable()]) }
#[allow(unused_variables)]
fn command(&self, ctx: SysCtx) -> OrcRes<Option<Expr>> { Err(err_not_command().into()) }
#[allow(unused_variables)]
fn print(&self, ctx: SysCtx) -> String { format!("ThinAtom({})", type_name::<Self>()) }
#[allow(unused_variables)]
fn call(&self, arg: ExprHandle) -> Expr { bot([err_not_callable()]) }
#[allow(unused_variables)]
fn command(&self, ctx: SysCtx) -> OrcRes<Option<Expr>> { Err(err_not_command().into()) }
#[allow(unused_variables)]
fn print(&self, ctx: SysCtx) -> String { format!("ThinAtom({})", type_name::<Self>()) }
}

View File

@@ -1,58 +1,58 @@
use orchid_base::error::{mk_err, OrcErr, OrcRes};
use orchid_base::error::{OrcErr, OrcRes, mk_err};
use orchid_base::intern;
use orchid_base::location::Pos;
use crate::atom::{AtomicFeatures, ToAtom, TypAtom};
use crate::expr::{atom, bot, Expr};
use crate::expr::{Expr, atom, bot};
use crate::system::downcast_atom;
pub trait TryFromExpr: Sized {
fn try_from_expr(expr: Expr) -> OrcRes<Self>;
fn try_from_expr(expr: Expr) -> OrcRes<Self>;
}
impl TryFromExpr for Expr {
fn try_from_expr(expr: Expr) -> OrcRes<Self> { Ok(expr) }
fn try_from_expr(expr: Expr) -> OrcRes<Self> { Ok(expr) }
}
impl<T: TryFromExpr, U: TryFromExpr> TryFromExpr for (T, U) {
fn try_from_expr(expr: Expr) -> OrcRes<Self> {
Ok((T::try_from_expr(expr.clone())?, U::try_from_expr(expr)?))
}
fn try_from_expr(expr: Expr) -> OrcRes<Self> {
Ok((T::try_from_expr(expr.clone())?, U::try_from_expr(expr)?))
}
}
fn err_not_atom(pos: Pos) -> OrcErr {
mk_err(intern!(str: "Expected an atom"), "This expression is not an atom", [pos.into()])
mk_err(intern!(str: "Expected an atom"), "This expression is not an atom", [pos.into()])
}
fn err_type(pos: Pos) -> OrcErr {
mk_err(intern!(str: "Type error"), "The atom is a different type than expected", [pos.into()])
mk_err(intern!(str: "Type error"), "The atom is a different type than expected", [pos.into()])
}
impl<A: AtomicFeatures> TryFromExpr for TypAtom<'_, A> {
fn try_from_expr(expr: Expr) -> OrcRes<Self> {
(expr.foreign_atom())
.map_err(|ex| err_not_atom(ex.pos.clone()).into())
.and_then(|f| downcast_atom(f).map_err(|f| err_type(f.pos).into()))
}
fn try_from_expr(expr: Expr) -> OrcRes<Self> {
(expr.foreign_atom())
.map_err(|ex| err_not_atom(ex.pos.clone()).into())
.and_then(|f| downcast_atom(f).map_err(|f| err_type(f.pos).into()))
}
}
pub trait ToExpr {
fn to_expr(self) -> Expr;
fn to_expr(self) -> Expr;
}
impl ToExpr for Expr {
fn to_expr(self) -> Expr { self }
fn to_expr(self) -> Expr { self }
}
impl<T: ToExpr> ToExpr for OrcRes<T> {
fn to_expr(self) -> Expr {
match self {
Err(e) => bot(e),
Ok(t) => t.to_expr(),
}
}
fn to_expr(self) -> Expr {
match self {
Err(e) => bot(e),
Ok(t) => t.to_expr(),
}
}
}
impl<A: ToAtom> ToExpr for A {
fn to_expr(self) -> Expr { atom(self) }
fn to_expr(self) -> Expr { atom(self) }
}

View File

@@ -6,10 +6,10 @@ use std::{mem, process, thread};
use hashbrown::HashMap;
use itertools::Itertools;
use orchid_api_traits::{enc_vec, Decode, Encode};
use orchid_api_traits::{Decode, Encode, enc_vec};
use orchid_base::char_filter::{char_filter_match, char_filter_union, mk_char_filter};
use orchid_base::clone;
use orchid_base::interner::{init_replica, sweep_replica, Tok};
use orchid_base::interner::{Tok, init_replica, sweep_replica};
use orchid_base::logging::Logger;
use orchid_base::macros::{mtreev_from_api, mtreev_to_api};
use orchid_base::name::{PathSlice, Sym};
@@ -22,283 +22,283 @@ use crate::api;
use crate::atom::{AtomCtx, AtomDynfo};
use crate::atom_owned::OBJ_STORE;
use crate::fs::VirtFS;
use crate::lexer::{err_cascade, err_not_applicable, LexContext};
use crate::macros::{apply_rule, RuleCtx};
use crate::lexer::{LexContext, err_cascade, err_not_applicable};
use crate::macros::{RuleCtx, apply_rule};
use crate::msg::{recv_parent_msg, send_parent_msg};
use crate::system::{atom_by_idx, SysCtx};
use crate::system::{SysCtx, atom_by_idx};
use crate::system_ctor::{CtedObj, DynSystemCtor};
use crate::tree::{do_extra, GenTok, GenTokTree, LazyMemberFactory, TIACtxImpl};
use crate::tree::{GenTok, GenTokTree, LazyMemberFactory, TIACtxImpl, do_extra};
pub type ExtReq = RequestHandle<api::ExtMsgSet>;
pub type ExtReqNot = ReqNot<api::ExtMsgSet>;
pub struct ExtensionData {
pub name: &'static str,
pub systems: &'static [&'static dyn DynSystemCtor],
pub name: &'static str,
pub systems: &'static [&'static dyn DynSystemCtor],
}
impl ExtensionData {
pub fn new(name: &'static str, systems: &'static [&'static dyn DynSystemCtor]) -> Self {
Self { name, systems }
}
pub fn main(self) { extension_main(self) }
pub fn new(name: &'static str, systems: &'static [&'static dyn DynSystemCtor]) -> Self {
Self { name, systems }
}
pub fn main(self) { extension_main(self) }
}
pub enum MemberRecord {
Gen(Sym, LazyMemberFactory),
Res,
Gen(Sym, LazyMemberFactory),
Res,
}
pub struct SystemRecord {
cted: CtedObj,
vfses: HashMap<api::VfsId, &'static dyn VirtFS>,
declfs: api::EagerVfs,
lazy_members: HashMap<api::TreeId, MemberRecord>,
cted: CtedObj,
vfses: HashMap<api::VfsId, &'static dyn VirtFS>,
declfs: api::EagerVfs,
lazy_members: HashMap<api::TreeId, MemberRecord>,
}
pub fn with_atom_record<T>(
get_sys_ctx: &impl Fn(api::SysId, ReqNot<api::ExtMsgSet>) -> SysCtx,
reqnot: ReqNot<api::ExtMsgSet>,
atom: &api::Atom,
cb: impl FnOnce(Box<dyn AtomDynfo>, SysCtx, api::AtomId, &[u8]) -> T,
get_sys_ctx: &impl Fn(api::SysId, ReqNot<api::ExtMsgSet>) -> SysCtx,
reqnot: ReqNot<api::ExtMsgSet>,
atom: &api::Atom,
cb: impl FnOnce(Box<dyn AtomDynfo>, SysCtx, api::AtomId, &[u8]) -> T,
) -> T {
let mut data = &atom.data[..];
let ctx = get_sys_ctx(atom.owner, reqnot);
let inst = ctx.cted.inst();
let id = api::AtomId::decode(&mut data);
let atom_record = atom_by_idx(inst.card(), id).expect("Atom ID reserved");
cb(atom_record, ctx, id, data)
let mut data = &atom.data[..];
let ctx = get_sys_ctx(atom.owner, reqnot);
let inst = ctx.cted.inst();
let id = api::AtomId::decode(&mut data);
let atom_record = atom_by_idx(inst.card(), id).expect("Atom ID reserved");
cb(atom_record, ctx, id, data)
}
pub fn extension_main(data: ExtensionData) {
if thread::Builder::new()
.name(format!("ext-main:{}", data.name))
.spawn(|| extension_main_logic(data))
.unwrap()
.join()
.is_err()
{
process::exit(-1)
}
if thread::Builder::new()
.name(format!("ext-main:{}", data.name))
.spawn(|| extension_main_logic(data))
.unwrap()
.join()
.is_err()
{
process::exit(-1)
}
}
fn extension_main_logic(data: ExtensionData) {
let api::HostHeader { log_strategy } = api::HostHeader::decode(&mut std::io::stdin().lock());
let mut buf = Vec::new();
let decls = (data.systems.iter().enumerate())
.map(|(id, sys)| (u16::try_from(id).expect("more than u16max system ctors"), sys))
.map(|(id, sys)| sys.decl(api::SysDeclId(NonZero::new(id + 1).unwrap())))
.collect_vec();
let systems = Arc::new(Mutex::new(HashMap::<api::SysId, SystemRecord>::new()));
api::ExtensionHeader { name: data.name.to_string(), systems: decls.clone() }.encode(&mut buf);
std::io::stdout().write_all(&buf).unwrap();
std::io::stdout().flush().unwrap();
let exiting = Arc::new(AtomicBool::new(false));
let logger = Arc::new(Logger::new(log_strategy));
let mk_ctx = clone!(logger, systems; move |id: api::SysId, reqnot: ReqNot<api::ExtMsgSet>| {
let cted = systems.lock().unwrap()[&id].cted.clone();
SysCtx { id, cted, logger: logger.clone(), reqnot }
});
let rn = ReqNot::<api::ExtMsgSet>::new(
clone!(logger; move |a, _| {
logger.log_buf("Upsending", a);
send_parent_msg(a).unwrap()
}),
clone!(systems, exiting, mk_ctx; move |n, reqnot| match n {
api::HostExtNotif::Exit => exiting.store(true, Ordering::Relaxed),
api::HostExtNotif::SystemDrop(api::SystemDrop(sys_id)) =>
mem::drop(systems.lock().unwrap().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)),
}),
clone!(systems, logger; move |hand, req| match req {
api::HostExtReq::Ping(ping@api::Ping) => hand.handle(&ping, &()),
api::HostExtReq::Sweep(sweep@api::Sweep) => hand.handle(&sweep, &sweep_replica()),
api::HostExtReq::SysReq(api::SysReq::NewSystem(new_sys)) => {
let i = decls.iter().enumerate().find(|(_, s)| s.id == new_sys.system).unwrap().0;
let cted = data.systems[i].new_system(&new_sys);
let mut vfses = HashMap::new();
let lex_filter = cted.inst().dyn_lexers().iter().fold(api::CharFilter(vec![]), |cf, lx| {
let lxcf = mk_char_filter(lx.char_filter().iter().cloned());
char_filter_union(&cf, &lxcf)
});
let mut lazy_mems = HashMap::new();
let ctx = SysCtx{
cted: cted.clone(),
id: new_sys.id,
logger: logger.clone(),
reqnot: hand.reqnot()
};
let mut tia_ctx = TIACtxImpl{
lazy: &mut lazy_mems,
sys: ctx.clone(),
basepath: &[],
path: Substack::Bottom,
};
let const_root = (cted.inst().dyn_env().into_iter())
.map(|(k, v)| (k.to_api(), v.into_api(&mut tia_ctx)))
.collect();
systems.lock().unwrap().insert(new_sys.id, SystemRecord {
declfs: cted.inst().dyn_vfs().to_api_rec(&mut vfses),
vfses,
cted,
lazy_members: lazy_mems
});
hand.handle(&new_sys, &api::SystemInst {
lex_filter,
const_root,
line_types: vec![]
})
}
api::HostExtReq::GetMember(get_tree@api::GetMember(sys_id, tree_id)) => {
let mut systems_g = systems.lock().unwrap();
let sys = systems_g.get_mut(&sys_id).expect("System not found");
let lazy = &mut sys.lazy_members;
let (path, cb) = match lazy.insert(tree_id, MemberRecord::Res) {
None => panic!("Tree for ID not found"),
Some(MemberRecord::Res) => panic!("This tree has already been transmitted"),
Some(MemberRecord::Gen(path, cb)) => (path, cb),
};
let tree = cb.build(path.clone());
hand.handle(&get_tree, &tree.into_api(&mut TIACtxImpl{
sys: SysCtx::new(sys_id, &sys.cted, &logger, hand.reqnot()),
path: Substack::Bottom,
basepath: &path,
lazy,
}))
}
api::HostExtReq::VfsReq(api::VfsReq::GetVfs(get_vfs@api::GetVfs(sys_id))) => {
let systems_g = systems.lock().unwrap();
hand.handle(&get_vfs, &systems_g[&sys_id].declfs)
}
api::HostExtReq::SysReq(api::SysReq::SysFwded(fwd)) => {
let api::SysFwded(sys_id, payload) = fwd;
let ctx = mk_ctx(sys_id, hand.reqnot());
let sys = ctx.cted.inst();
sys.dyn_request(hand, payload)
}
api::HostExtReq::VfsReq(api::VfsReq::VfsRead(vfs_read)) => {
let api::VfsRead(sys_id, vfs_id, path) = &vfs_read;
let systems_g = systems.lock().unwrap();
let path = path.iter().map(|t| Tok::from_api(*t)).collect_vec();
hand.handle(&vfs_read, &systems_g[sys_id].vfses[vfs_id].load(PathSlice::new(&path)))
}
api::HostExtReq::LexExpr(lex @ api::LexExpr{ sys, text, pos, id }) => {
let systems_g = systems.lock().unwrap();
let lexers = systems_g[&sys].cted.inst().dyn_lexers();
mem::drop(systems_g);
let text = Tok::from_api(text);
let ctx = LexContext { sys, id, pos, reqnot: hand.reqnot(), text: &text };
let trigger_char = text.chars().nth(pos as usize).unwrap();
for lx in lexers.iter().filter(|l| char_filter_match(l.char_filter(), trigger_char)) {
match lx.lex(&text[pos as usize..], &ctx) {
Err(e) if e.any(|e| *e == err_not_applicable()) => continue,
Err(e) => {
let eopt = e.keep_only(|e| *e != err_cascade()).map(|e| Err(e.to_api()));
return hand.handle(&lex, &eopt)
},
Ok((s, expr)) => {
let ctx = mk_ctx(sys, hand.reqnot());
let expr = expr.to_api(&mut |f, r| do_extra(f, r, ctx.clone()));
let pos = (text.len() - s.len()) as u32;
return hand.handle(&lex, &Some(Ok(api::LexedExpr{ pos, expr })))
}
}
}
writeln!(logger, "Got notified about n/a character '{trigger_char}'");
hand.handle(&lex, &None)
},
api::HostExtReq::ParseLine(pline) => {
let api::ParseLine{ exported, comments, sys, line } = &pline;
let mut ctx = mk_ctx(*sys, hand.reqnot());
let parsers = ctx.cted.inst().dyn_parsers();
let comments = comments.iter().map(Comment::from_api).collect();
let line: Vec<GenTokTree> = ttv_from_api(line, &mut ctx);
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) {
Err(e) => Err(e.to_api()),
Ok(t) => Ok(ttv_to_api(t, &mut |f, range| {
api::TokenTree{ range, token: api::Token::Atom(f.clone().build(ctx.clone())) }
})),
};
hand.handle(&pline, &o_line)
}
api::HostExtReq::AtomReq(atom_req) => {
let atom = atom_req.get_atom();
with_atom_record(&mk_ctx, hand.reqnot(), atom, |nfo, ctx, id, buf| {
let actx = AtomCtx(buf, atom.drop, ctx.clone());
match &atom_req {
api::AtomReq::SerializeAtom(ser) => {
let mut buf = enc_vec(&id);
let refs_opt = nfo.serialize(actx, &mut buf);
hand.handle(ser, &refs_opt.map(|refs| (buf, refs)))
}
api::AtomReq::AtomPrint(print@api::AtomPrint(_)) =>
hand.handle(print, &nfo.print(actx)),
api::AtomReq::Fwded(fwded) => {
let api::Fwded(_, key, payload) = &fwded;
let mut reply = Vec::new();
let some = nfo.handle_req(actx, Sym::from_api(*key), &mut &payload[..], &mut reply);
hand.handle(fwded, &some.then_some(reply))
}
api::AtomReq::CallRef(call@api::CallRef(_, arg)) => {
let ret = nfo.call_ref(actx, *arg);
hand.handle(call, &ret.api_return(ctx.clone(), &mut |h| hand.defer_drop(h)))
},
api::AtomReq::FinalCall(call@api::FinalCall(_, arg)) => {
let ret = nfo.call(actx, *arg);
hand.handle(call, &ret.api_return(ctx.clone(), &mut |h| hand.defer_drop(h)))
}
api::AtomReq::Command(cmd@api::Command(_)) => {
hand.handle(cmd, &match nfo.command(actx) {
Err(e) => Err(e.to_api()),
Ok(opt) => Ok(match opt {
None => api::NextStep::Halt,
Some(cont) => api::NextStep::Continue(
cont.api_return(ctx.clone(), &mut |h| hand.defer_drop(h))
),
})
})
}
}
})
},
api::HostExtReq::DeserAtom(deser) => {
let api::DeserAtom(sys, buf, refs) = &deser;
let mut read = &mut &buf[..];
let ctx = mk_ctx(*sys, hand.reqnot());
let id = api::AtomId::decode(&mut read);
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))
},
orchid_api::HostExtReq::ApplyMacro(am) => {
let tok = hand.will_handle_as(&am);
let sys_ctx = mk_ctx(am.sys, hand.reqnot());
let ctx = RuleCtx {
args: (am.params.into_iter())
.map(|(k, v)| (
Tok::from_api(k),
mtreev_from_api(&v, &mut |_| panic!("No atom in macro prompt!"))
))
.collect(),
run_id: am.run_id,
sys: sys_ctx.clone(),
};
hand.handle_as(tok, &match apply_rule(am.id, ctx) {
Err(e) => e.keep_only(|e| *e != err_cascade()).map(|e| Err(e.to_api())),
Ok(t) => Some(Ok(mtreev_to_api(&t, &mut |a| {
api::MacroToken::Atom(a.clone().build(sys_ctx.clone()))
}))),
})
}
}),
);
init_replica(rn.clone().map());
while !exiting.load(Ordering::Relaxed) {
let rcvd = recv_parent_msg().unwrap();
rn.receive(&rcvd)
}
let api::HostHeader { log_strategy } = api::HostHeader::decode(&mut std::io::stdin().lock());
let mut buf = Vec::new();
let decls = (data.systems.iter().enumerate())
.map(|(id, sys)| (u16::try_from(id).expect("more than u16max system ctors"), sys))
.map(|(id, sys)| sys.decl(api::SysDeclId(NonZero::new(id + 1).unwrap())))
.collect_vec();
let systems = Arc::new(Mutex::new(HashMap::<api::SysId, SystemRecord>::new()));
api::ExtensionHeader { name: data.name.to_string(), systems: decls.clone() }.encode(&mut buf);
std::io::stdout().write_all(&buf).unwrap();
std::io::stdout().flush().unwrap();
let exiting = Arc::new(AtomicBool::new(false));
let logger = Arc::new(Logger::new(log_strategy));
let mk_ctx = clone!(logger, systems; move |id: api::SysId, reqnot: ReqNot<api::ExtMsgSet>| {
let cted = systems.lock().unwrap()[&id].cted.clone();
SysCtx { id, cted, logger: logger.clone(), reqnot }
});
let rn = ReqNot::<api::ExtMsgSet>::new(
clone!(logger; move |a, _| {
logger.log_buf("Upsending", a);
send_parent_msg(a).unwrap()
}),
clone!(systems, exiting, mk_ctx; move |n, reqnot| match n {
api::HostExtNotif::Exit => exiting.store(true, Ordering::Relaxed),
api::HostExtNotif::SystemDrop(api::SystemDrop(sys_id)) =>
mem::drop(systems.lock().unwrap().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)),
}),
clone!(systems, logger; move |hand, req| match req {
api::HostExtReq::Ping(ping@api::Ping) => hand.handle(&ping, &()),
api::HostExtReq::Sweep(sweep@api::Sweep) => hand.handle(&sweep, &sweep_replica()),
api::HostExtReq::SysReq(api::SysReq::NewSystem(new_sys)) => {
let i = decls.iter().enumerate().find(|(_, s)| s.id == new_sys.system).unwrap().0;
let cted = data.systems[i].new_system(&new_sys);
let mut vfses = HashMap::new();
let lex_filter = cted.inst().dyn_lexers().iter().fold(api::CharFilter(vec![]), |cf, lx| {
let lxcf = mk_char_filter(lx.char_filter().iter().cloned());
char_filter_union(&cf, &lxcf)
});
let mut lazy_mems = HashMap::new();
let ctx = SysCtx{
cted: cted.clone(),
id: new_sys.id,
logger: logger.clone(),
reqnot: hand.reqnot()
};
let mut tia_ctx = TIACtxImpl{
lazy: &mut lazy_mems,
sys: ctx.clone(),
basepath: &[],
path: Substack::Bottom,
};
let const_root = (cted.inst().dyn_env().into_iter())
.map(|(k, v)| (k.to_api(), v.into_api(&mut tia_ctx)))
.collect();
systems.lock().unwrap().insert(new_sys.id, SystemRecord {
declfs: cted.inst().dyn_vfs().to_api_rec(&mut vfses),
vfses,
cted,
lazy_members: lazy_mems
});
hand.handle(&new_sys, &api::SystemInst {
lex_filter,
const_root,
line_types: vec![]
})
}
api::HostExtReq::GetMember(get_tree@api::GetMember(sys_id, tree_id)) => {
let mut systems_g = systems.lock().unwrap();
let sys = systems_g.get_mut(&sys_id).expect("System not found");
let lazy = &mut sys.lazy_members;
let (path, cb) = match lazy.insert(tree_id, MemberRecord::Res) {
None => panic!("Tree for ID not found"),
Some(MemberRecord::Res) => panic!("This tree has already been transmitted"),
Some(MemberRecord::Gen(path, cb)) => (path, cb),
};
let tree = cb.build(path.clone());
hand.handle(&get_tree, &tree.into_api(&mut TIACtxImpl{
sys: SysCtx::new(sys_id, &sys.cted, &logger, hand.reqnot()),
path: Substack::Bottom,
basepath: &path,
lazy,
}))
}
api::HostExtReq::VfsReq(api::VfsReq::GetVfs(get_vfs@api::GetVfs(sys_id))) => {
let systems_g = systems.lock().unwrap();
hand.handle(&get_vfs, &systems_g[&sys_id].declfs)
}
api::HostExtReq::SysReq(api::SysReq::SysFwded(fwd)) => {
let api::SysFwded(sys_id, payload) = fwd;
let ctx = mk_ctx(sys_id, hand.reqnot());
let sys = ctx.cted.inst();
sys.dyn_request(hand, payload)
}
api::HostExtReq::VfsReq(api::VfsReq::VfsRead(vfs_read)) => {
let api::VfsRead(sys_id, vfs_id, path) = &vfs_read;
let systems_g = systems.lock().unwrap();
let path = path.iter().map(|t| Tok::from_api(*t)).collect_vec();
hand.handle(&vfs_read, &systems_g[sys_id].vfses[vfs_id].load(PathSlice::new(&path)))
}
api::HostExtReq::LexExpr(lex @ api::LexExpr{ sys, text, pos, id }) => {
let systems_g = systems.lock().unwrap();
let lexers = systems_g[&sys].cted.inst().dyn_lexers();
mem::drop(systems_g);
let text = Tok::from_api(text);
let ctx = LexContext { sys, id, pos, reqnot: hand.reqnot(), text: &text };
let trigger_char = text.chars().nth(pos as usize).unwrap();
for lx in lexers.iter().filter(|l| char_filter_match(l.char_filter(), trigger_char)) {
match lx.lex(&text[pos as usize..], &ctx) {
Err(e) if e.any(|e| *e == err_not_applicable()) => continue,
Err(e) => {
let eopt = e.keep_only(|e| *e != err_cascade()).map(|e| Err(e.to_api()));
return hand.handle(&lex, &eopt)
},
Ok((s, expr)) => {
let ctx = mk_ctx(sys, hand.reqnot());
let expr = expr.to_api(&mut |f, r| do_extra(f, r, ctx.clone()));
let pos = (text.len() - s.len()) as u32;
return hand.handle(&lex, &Some(Ok(api::LexedExpr{ pos, expr })))
}
}
}
writeln!(logger, "Got notified about n/a character '{trigger_char}'");
hand.handle(&lex, &None)
},
api::HostExtReq::ParseLine(pline) => {
let api::ParseLine{ exported, comments, sys, line } = &pline;
let mut ctx = mk_ctx(*sys, hand.reqnot());
let parsers = ctx.cted.inst().dyn_parsers();
let comments = comments.iter().map(Comment::from_api).collect();
let line: Vec<GenTokTree> = ttv_from_api(line, &mut ctx);
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) {
Err(e) => Err(e.to_api()),
Ok(t) => Ok(ttv_to_api(t, &mut |f, range| {
api::TokenTree{ range, token: api::Token::Atom(f.clone().build(ctx.clone())) }
})),
};
hand.handle(&pline, &o_line)
}
api::HostExtReq::AtomReq(atom_req) => {
let atom = atom_req.get_atom();
with_atom_record(&mk_ctx, hand.reqnot(), atom, |nfo, ctx, id, buf| {
let actx = AtomCtx(buf, atom.drop, ctx.clone());
match &atom_req {
api::AtomReq::SerializeAtom(ser) => {
let mut buf = enc_vec(&id);
let refs_opt = nfo.serialize(actx, &mut buf);
hand.handle(ser, &refs_opt.map(|refs| (buf, refs)))
}
api::AtomReq::AtomPrint(print@api::AtomPrint(_)) =>
hand.handle(print, &nfo.print(actx)),
api::AtomReq::Fwded(fwded) => {
let api::Fwded(_, key, payload) = &fwded;
let mut reply = Vec::new();
let some = nfo.handle_req(actx, Sym::from_api(*key), &mut &payload[..], &mut reply);
hand.handle(fwded, &some.then_some(reply))
}
api::AtomReq::CallRef(call@api::CallRef(_, arg)) => {
let ret = nfo.call_ref(actx, *arg);
hand.handle(call, &ret.api_return(ctx.clone(), &mut |h| hand.defer_drop(h)))
},
api::AtomReq::FinalCall(call@api::FinalCall(_, arg)) => {
let ret = nfo.call(actx, *arg);
hand.handle(call, &ret.api_return(ctx.clone(), &mut |h| hand.defer_drop(h)))
}
api::AtomReq::Command(cmd@api::Command(_)) => {
hand.handle(cmd, &match nfo.command(actx) {
Err(e) => Err(e.to_api()),
Ok(opt) => Ok(match opt {
None => api::NextStep::Halt,
Some(cont) => api::NextStep::Continue(
cont.api_return(ctx.clone(), &mut |h| hand.defer_drop(h))
),
})
})
}
}
})
},
api::HostExtReq::DeserAtom(deser) => {
let api::DeserAtom(sys, buf, refs) = &deser;
let mut read = &mut &buf[..];
let ctx = mk_ctx(*sys, hand.reqnot());
let id = api::AtomId::decode(&mut read);
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))
},
orchid_api::HostExtReq::ApplyMacro(am) => {
let tok = hand.will_handle_as(&am);
let sys_ctx = mk_ctx(am.sys, hand.reqnot());
let ctx = RuleCtx {
args: (am.params.into_iter())
.map(|(k, v)| (
Tok::from_api(k),
mtreev_from_api(&v, &mut |_| panic!("No atom in macro prompt!"))
))
.collect(),
run_id: am.run_id,
sys: sys_ctx.clone(),
};
hand.handle_as(tok, &match apply_rule(am.id, ctx) {
Err(e) => e.keep_only(|e| *e != err_cascade()).map(|e| Err(e.to_api())),
Ok(t) => Some(Ok(mtreev_to_api(&t, &mut |a| {
api::MacroToken::Atom(a.clone().build(sys_ctx.clone()))
}))),
})
}
}),
);
init_replica(rn.clone().map());
while !exiting.load(Ordering::Relaxed) {
let rcvd = recv_parent_msg().unwrap();
rn.receive(&rcvd)
}
}

View File

@@ -1,9 +1,8 @@
use std::fmt;
use std::ops::Deref;
use std::sync::{Arc, OnceLock};
use std::{backtrace, fmt};
use derive_destructure::destructure;
use orchid_base::clone;
use orchid_base::error::{OrcErr, OrcErrv};
use orchid_base::interner::Tok;
use orchid_base::location::Pos;
@@ -17,122 +16,122 @@ use crate::system::SysCtx;
#[derive(destructure)]
pub struct ExprHandle {
pub tk: api::ExprTicket,
pub ctx: SysCtx,
pub tk: api::ExprTicket,
pub ctx: SysCtx,
}
impl ExprHandle {
pub(crate) fn from_args(ctx: SysCtx, tk: api::ExprTicket) -> Self { Self { ctx, tk } }
pub fn get_ctx(&self) -> SysCtx { self.ctx.clone() }
pub(crate) fn from_args(ctx: SysCtx, tk: api::ExprTicket) -> Self { Self { ctx, tk } }
pub fn get_ctx(&self) -> SysCtx { self.ctx.clone() }
}
impl fmt::Debug for ExprHandle {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "ExprHandle({})", self.tk.0)
}
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "ExprHandle({})", self.tk.0)
}
}
impl Clone for ExprHandle {
fn clone(&self) -> Self {
self.ctx.reqnot.notify(api::Acquire(self.ctx.id, self.tk));
Self { ctx: self.ctx.clone(), tk: self.tk }
}
fn clone(&self) -> Self {
self.ctx.reqnot.notify(api::Acquire(self.ctx.id, self.tk));
Self { ctx: self.ctx.clone(), tk: self.tk }
}
}
impl Drop for ExprHandle {
fn drop(&mut self) { self.ctx.reqnot.notify(api::Release(self.ctx.id, self.tk)) }
fn drop(&mut self) { self.ctx.reqnot.notify(api::Release(self.ctx.id, self.tk)) }
}
#[derive(Clone, Debug, destructure)]
pub struct Expr {
pub handle: Option<Arc<ExprHandle>>,
pub val: OnceLock<ExprData>,
pub handle: Option<Arc<ExprHandle>>,
pub val: OnceLock<ExprData>,
}
impl Expr {
pub fn new(hand: Arc<ExprHandle>) -> Self { Self { handle: Some(hand), val: OnceLock::new() } }
pub fn from_data(val: ExprData) -> Self { Self { handle: None, val: OnceLock::from(val) } }
pub fn get_data(&self) -> &ExprData {
self.val.get_or_init(|| {
let handle = self.handle.as_ref().expect("Either the value or the handle must be set");
let details = handle.ctx.reqnot.request(api::Inspect { target: handle.tk });
let pos = Pos::from_api(&details.location);
let kind = match details.kind {
api::InspectedKind::Atom(a) =>
ExprKind::Atom(ForeignAtom::new(handle.clone(), a, pos.clone())),
api::InspectedKind::Bottom(b) => ExprKind::Bottom(OrcErrv::from_api(&b)),
api::InspectedKind::Opaque => ExprKind::Opaque,
};
ExprData { pos, kind }
})
}
pub fn foreign_atom(self) -> Result<ForeignAtom<'static>, Self> {
match (self.get_data(), &self.handle) {
(ExprData { kind: ExprKind::Atom(atom), .. }, Some(_)) => Ok(atom.clone()),
_ => Err(self),
}
}
pub fn api_return(
self,
ctx: SysCtx,
do_slot: &mut impl FnMut(Arc<ExprHandle>),
) -> api::Expression {
if let Some(h) = self.handle {
do_slot(h.clone());
api::Expression { location: api::Location::SlotTarget, kind: api::ExpressionKind::Slot(h.tk) }
} else {
self.val.into_inner().expect("Either value or handle must be set").api_return(ctx, do_slot)
}
}
pub fn handle(&self) -> Option<Arc<ExprHandle>> { self.handle.clone() }
pub fn new(hand: Arc<ExprHandle>) -> Self { Self { handle: Some(hand), val: OnceLock::new() } }
pub fn from_data(val: ExprData) -> Self { Self { handle: None, val: OnceLock::from(val) } }
pub fn get_data(&self) -> &ExprData {
self.val.get_or_init(|| {
let handle = self.handle.as_ref().expect("Either the value or the handle must be set");
let details = handle.ctx.reqnot.request(api::Inspect { target: handle.tk });
let pos = Pos::from_api(&details.location);
let kind = match details.kind {
api::InspectedKind::Atom(a) =>
ExprKind::Atom(ForeignAtom::new(handle.clone(), a, pos.clone())),
api::InspectedKind::Bottom(b) => ExprKind::Bottom(OrcErrv::from_api(&b)),
api::InspectedKind::Opaque => ExprKind::Opaque,
};
ExprData { pos, kind }
})
}
pub fn foreign_atom(self) -> Result<ForeignAtom<'static>, Self> {
match (self.get_data(), &self.handle) {
(ExprData { kind: ExprKind::Atom(atom), .. }, Some(_)) => Ok(atom.clone()),
_ => Err(self),
}
}
pub fn api_return(
self,
ctx: SysCtx,
do_slot: &mut impl FnMut(Arc<ExprHandle>),
) -> api::Expression {
if let Some(h) = self.handle {
do_slot(h.clone());
api::Expression { location: api::Location::SlotTarget, kind: api::ExpressionKind::Slot(h.tk) }
} else {
self.val.into_inner().expect("Either value or handle must be set").api_return(ctx, do_slot)
}
}
pub fn handle(&self) -> Option<Arc<ExprHandle>> { self.handle.clone() }
}
impl Deref for Expr {
type Target = ExprData;
fn deref(&self) -> &Self::Target { self.get_data() }
type Target = ExprData;
fn deref(&self) -> &Self::Target { self.get_data() }
}
#[derive(Clone, Debug)]
pub struct ExprData {
pub pos: Pos,
pub kind: ExprKind,
pub pos: Pos,
pub kind: ExprKind,
}
impl ExprData {
pub fn api_return(
self,
ctx: SysCtx,
do_slot: &mut impl FnMut(Arc<ExprHandle>),
) -> api::Expression {
api::Expression { location: self.pos.to_api(), kind: self.kind.api_return(ctx, do_slot) }
}
pub fn api_return(
self,
ctx: SysCtx,
do_slot: &mut impl FnMut(Arc<ExprHandle>),
) -> api::Expression {
api::Expression { location: self.pos.to_api(), kind: self.kind.api_return(ctx, do_slot) }
}
}
#[derive(Clone, Debug)]
pub enum ExprKind {
Call(Box<Expr>, Box<Expr>),
Lambda(u64, Box<Expr>),
Arg(u64),
Seq(Box<Expr>, Box<Expr>),
Const(Tok<Vec<Tok<String>>>),
NewAtom(AtomFactory),
Atom(ForeignAtom<'static>),
Bottom(OrcErrv),
Opaque,
Call(Box<Expr>, Box<Expr>),
Lambda(u64, Box<Expr>),
Arg(u64),
Seq(Box<Expr>, Box<Expr>),
Const(Tok<Vec<Tok<String>>>),
NewAtom(AtomFactory),
Atom(ForeignAtom<'static>),
Bottom(OrcErrv),
Opaque,
}
impl ExprKind {
pub fn api_return(
self,
ctx: SysCtx,
do_slot: &mut impl FnMut(Arc<ExprHandle>),
) -> api::ExpressionKind {
use api::ExpressionKind as K;
match self {
Self::Call(f, x) =>
K::Call(Box::new(f.api_return(ctx.clone(), do_slot)), Box::new(x.api_return(ctx, do_slot))),
Self::Seq(a, b) =>
K::Seq(Box::new(a.api_return(ctx.clone(), do_slot)), Box::new(b.api_return(ctx, do_slot))),
Self::Lambda(arg, body) => K::Lambda(arg, Box::new(body.api_return(ctx, do_slot))),
Self::Arg(arg) => K::Arg(arg),
Self::Const(name) => K::Const(name.to_api()),
Self::Bottom(err) => K::Bottom(err.to_api()),
Self::NewAtom(fac) => K::NewAtom(fac.clone().build(ctx)),
kind @ (Self::Atom(_) | Self::Opaque) => panic!("{kind:?} should have a token"),
}
}
pub fn api_return(
self,
ctx: SysCtx,
do_slot: &mut impl FnMut(Arc<ExprHandle>),
) -> api::ExpressionKind {
use api::ExpressionKind as K;
match self {
Self::Call(f, x) =>
K::Call(Box::new(f.api_return(ctx.clone(), do_slot)), Box::new(x.api_return(ctx, do_slot))),
Self::Seq(a, b) =>
K::Seq(Box::new(a.api_return(ctx.clone(), do_slot)), Box::new(b.api_return(ctx, do_slot))),
Self::Lambda(arg, body) => K::Lambda(arg, Box::new(body.api_return(ctx, do_slot))),
Self::Arg(arg) => K::Arg(arg),
Self::Const(name) => K::Const(name.to_api()),
Self::Bottom(err) => K::Bottom(err.to_api()),
Self::NewAtom(fac) => K::NewAtom(fac.clone().build(ctx)),
kind @ (Self::Atom(_) | Self::Opaque) => panic!("{kind:?} should have a token"),
}
}
}
fn inherit(kind: ExprKind) -> Expr { Expr::from_data(ExprData { pos: Pos::Inherit, kind }) }
@@ -140,35 +139,35 @@ pub fn sym_ref(path: Tok<Vec<Tok<String>>>) -> Expr { inherit(ExprKind::Const(pa
pub fn atom<A: ToAtom>(atom: A) -> Expr { inherit(ExprKind::NewAtom(atom.to_atom_factory())) }
pub fn seq(ops: impl IntoIterator<Item = Expr>) -> Expr {
fn recur(mut ops: impl Iterator<Item = Expr>) -> Option<Expr> {
let op = ops.next()?;
Some(match recur(ops) {
None => op,
Some(rec) => inherit(ExprKind::Seq(Box::new(op), Box::new(rec))),
})
}
recur(ops.into_iter()).expect("Empty list provided to seq!")
fn recur(mut ops: impl Iterator<Item = Expr>) -> Option<Expr> {
let op = ops.next()?;
Some(match recur(ops) {
None => op,
Some(rec) => inherit(ExprKind::Seq(Box::new(op), Box::new(rec))),
})
}
recur(ops.into_iter()).expect("Empty list provided to seq!")
}
pub fn arg(n: u64) -> Expr { inherit(ExprKind::Arg(n)) }
pub fn lambda(n: u64, b: impl IntoIterator<Item = Expr>) -> Expr {
inherit(ExprKind::Lambda(n, Box::new(call(b))))
inherit(ExprKind::Lambda(n, Box::new(call(b))))
}
pub fn call(v: impl IntoIterator<Item = Expr>) -> Expr {
v.into_iter()
.reduce(|f, x| inherit(ExprKind::Call(Box::new(f), Box::new(x))))
.expect("Empty call expression")
v.into_iter()
.reduce(|f, x| inherit(ExprKind::Call(Box::new(f), Box::new(x))))
.expect("Empty call expression")
}
pub fn bot(ev: impl IntoIterator<Item = OrcErr>) -> Expr {
inherit(ExprKind::Bottom(OrcErrv::new(ev).unwrap()))
inherit(ExprKind::Bottom(OrcErrv::new(ev).unwrap()))
}
pub fn with<I: TryFromExpr, O: ToExpr>(
expr: Expr,
cont: impl Fn(I) -> O + Clone + Send + Sync + 'static,
expr: Expr,
cont: impl Fn(I) -> O + Clone + Send + Sync + 'static,
) -> Expr {
call([lambda(0, [seq([arg(0), call([Lambda::new(cont).to_expr(), arg(0)])])]), expr])
call([lambda(0, [seq([arg(0), call([Lambda::new(cont).to_expr(), arg(0)])])]), expr])
}

View File

@@ -7,25 +7,25 @@ use orchid_base::name::PathSlice;
use crate::api;
pub trait VirtFS: Send + Sync + 'static {
fn load(&self, path: &PathSlice) -> api::OrcResult<api::Loaded>;
fn load(&self, path: &PathSlice) -> api::OrcResult<api::Loaded>;
}
pub enum DeclFs {
Lazy(&'static dyn VirtFS),
Mod(&'static [(&'static str, DeclFs)]),
Lazy(&'static dyn VirtFS),
Mod(&'static [(&'static str, DeclFs)]),
}
impl DeclFs {
pub fn to_api_rec(&self, vfses: &mut HashMap<api::VfsId, &'static dyn VirtFS>) -> api::EagerVfs {
match self {
DeclFs::Lazy(fs) => {
let vfsc: u16 = vfses.len().try_into().expect("too many vfses (more than u16::MAX)");
let id = api::VfsId(NonZero::new(vfsc + 1).unwrap());
vfses.insert(id, *fs);
api::EagerVfs::Lazy(id)
},
DeclFs::Mod(children) => api::EagerVfs::Eager(
children.iter().map(|(k, v)| (intern(*k).to_api(), v.to_api_rec(vfses))).collect(),
),
}
}
pub fn to_api_rec(&self, vfses: &mut HashMap<api::VfsId, &'static dyn VirtFS>) -> api::EagerVfs {
match self {
DeclFs::Lazy(fs) => {
let vfsc: u16 = vfses.len().try_into().expect("too many vfses (more than u16::MAX)");
let id = api::VfsId(NonZero::new(vfsc + 1).unwrap());
vfses.insert(id, *fs);
api::EagerVfs::Lazy(id)
},
DeclFs::Mod(children) => api::EagerVfs::Eager(
children.iter().map(|(k, v)| (intern(*k).to_api(), v.to_api_rec(vfses))).collect(),
),
}
}
}

View File

@@ -19,114 +19,115 @@ use crate::expr::{Expr, ExprHandle};
use crate::system::SysCtx;
trait_set! {
trait FunCB = Fn(Vec<Expr>) -> OrcRes<Expr> + Send + Sync + 'static;
trait FunCB = Fn(Vec<Expr>) -> OrcRes<Expr> + Send + Sync + 'static;
}
pub trait ExprFunc<I, O>: Clone + Send + Sync + 'static {
const ARITY: u8;
fn apply(&self, v: Vec<Expr>) -> OrcRes<Expr>;
const ARITY: u8;
fn apply(&self, v: Vec<Expr>) -> OrcRes<Expr>;
}
lazy_static! {
static ref FUNS: Mutex<HashMap<Sym, (u8, Arc<dyn FunCB>)>> = Mutex::default();
static ref FUNS: Mutex<HashMap<Sym, (u8, Arc<dyn FunCB>)>> = Mutex::default();
}
/// An Atom representing a partially applied named native function. These
/// partial calls are serialized into the name of the native function and the
/// argument list.
///
///
/// See [Lambda] for the non-serializable variant
#[derive(Clone)]
pub(crate) struct Fun {
path: Sym,
args: Vec<Expr>,
arity: u8,
fun: Arc<dyn FunCB>,
path: Sym,
args: Vec<Expr>,
arity: u8,
fun: Arc<dyn FunCB>,
}
impl Fun {
pub fn new<I, O, F: ExprFunc<I, O>>(path: Sym, f: F) -> Self {
let mut fung = FUNS.lock().unwrap();
let fun = if let Some(x) = fung.get(&path) {
x.1.clone()
} else {
let fun = Arc::new(move |v| f.apply(v));
fung.insert(path.clone(), (F::ARITY, fun.clone()));
fun
};
Self { args: vec![], arity: F::ARITY, path, fun }
}
pub fn new<I, O, F: ExprFunc<I, O>>(path: Sym, f: F) -> Self {
let mut fung = FUNS.lock().unwrap();
let fun = if let Some(x) = fung.get(&path) {
x.1.clone()
} else {
let fun = Arc::new(move |v| f.apply(v));
fung.insert(path.clone(), (F::ARITY, fun.clone()));
fun
};
Self { args: vec![], arity: F::ARITY, path, fun }
}
}
impl Atomic for Fun {
type Data = ();
type Variant = OwnedVariant;
fn reg_reqs() -> MethodSet<Self> { MethodSet::new() }
type Data = ();
type Variant = OwnedVariant;
fn reg_reqs() -> MethodSet<Self> { MethodSet::new() }
}
impl OwnedAtom for Fun {
type Refs = Vec<Expr>;
fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) }
fn call_ref(&self, arg: ExprHandle) -> Expr {
let new_args = self.args.iter().cloned().chain([Expr::new(Arc::new(arg))]).collect_vec();
if new_args.len() == self.arity.into() {
(self.fun)(new_args).to_expr()
} else {
Self { args: new_args, arity: self.arity, fun: self.fun.clone(), path: self.path.clone() }
.to_expr()
}
}
fn call(self, arg: ExprHandle) -> Expr { self.call_ref(arg) }
fn serialize(&self, _: SysCtx, sink: &mut (impl io::Write + ?Sized)) -> Self::Refs {
self.path.encode(sink);
self.args.clone()
}
fn deserialize(ctx: impl DeserializeCtx, args: Self::Refs) -> Self {
let path = Sym::new(ctx.decode::<Vec<Tok<String>>>()).unwrap();
let (arity, fun) = FUNS.lock().unwrap().get(&path).unwrap().clone();
Self { args, arity, path, fun }
}
type Refs = Vec<Expr>;
fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) }
fn call_ref(&self, arg: ExprHandle) -> Expr {
let new_args = self.args.iter().cloned().chain([Expr::new(Arc::new(arg))]).collect_vec();
if new_args.len() == self.arity.into() {
(self.fun)(new_args).to_expr()
} else {
Self { args: new_args, arity: self.arity, fun: self.fun.clone(), path: self.path.clone() }
.to_expr()
}
}
fn call(self, arg: ExprHandle) -> Expr { self.call_ref(arg) }
fn serialize(&self, _: SysCtx, sink: &mut (impl io::Write + ?Sized)) -> Self::Refs {
self.path.encode(sink);
self.args.clone()
}
fn deserialize(ctx: impl DeserializeCtx, args: Self::Refs) -> Self {
let path = Sym::new(ctx.decode::<Vec<Tok<String>>>()).unwrap();
let (arity, fun) = FUNS.lock().unwrap().get(&path).unwrap().clone();
Self { args, arity, path, fun }
}
}
/// An Atom representing a partially applied native lambda. These are not serializable.
///
/// An Atom representing a partially applied native lambda. These are not
/// serializable.
///
/// See [Fun] for the serializable variant
#[derive(Clone)]
pub struct Lambda {
args: Vec<Expr>,
arity: u8,
fun: Arc<dyn FunCB>,
args: Vec<Expr>,
arity: u8,
fun: Arc<dyn FunCB>,
}
impl Lambda {
pub fn new<I, O, F: ExprFunc<I, O>>(f: F) -> Self {
let fun = Arc::new(move |v| f.apply(v));
Self { args: vec![], arity: F::ARITY, fun }
}
pub fn new<I, O, F: ExprFunc<I, O>>(f: F) -> Self {
let fun = Arc::new(move |v| f.apply(v));
Self { args: vec![], arity: F::ARITY, fun }
}
}
impl Atomic for Lambda {
type Data = ();
type Variant = OwnedVariant;
fn reg_reqs() -> MethodSet<Self> { MethodSet::new() }
type Data = ();
type Variant = OwnedVariant;
fn reg_reqs() -> MethodSet<Self> { MethodSet::new() }
}
impl OwnedAtom for Lambda {
type Refs = Never;
fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) }
fn call_ref(&self, arg: ExprHandle) -> Expr {
let new_args = self.args.iter().cloned().chain([Expr::new(Arc::new(arg))]).collect_vec();
if new_args.len() == self.arity.into() {
(self.fun)(new_args).to_expr()
} else {
Self { args: new_args, arity: self.arity, fun: self.fun.clone() }.to_expr()
}
}
fn call(self, arg: ExprHandle) -> Expr { self.call_ref(arg) }
type Refs = Never;
fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) }
fn call_ref(&self, arg: ExprHandle) -> Expr {
let new_args = self.args.iter().cloned().chain([Expr::new(Arc::new(arg))]).collect_vec();
if new_args.len() == self.arity.into() {
(self.fun)(new_args).to_expr()
} else {
Self { args: new_args, arity: self.arity, fun: self.fun.clone() }.to_expr()
}
}
fn call(self, arg: ExprHandle) -> Expr { self.call_ref(arg) }
}
mod expr_func_derives {
use orchid_base::error::OrcRes;
use orchid_base::error::OrcRes;
use super::ExprFunc;
use crate::conv::{ToExpr, TryFromExpr};
use crate::func_atom::Expr;
use super::ExprFunc;
use crate::conv::{ToExpr, TryFromExpr};
use crate::func_atom::Expr;
macro_rules! expr_func_derive {
macro_rules! expr_func_derive {
($arity: tt, $($t:ident),*) => {
paste::paste!{
impl<
@@ -144,18 +145,18 @@ mod expr_func_derives {
}
};
}
expr_func_derive!(1, A);
expr_func_derive!(2, A, B);
expr_func_derive!(3, A, B, C);
expr_func_derive!(4, A, B, C, D);
expr_func_derive!(5, A, B, C, D, E);
expr_func_derive!(6, A, B, C, D, E, F);
expr_func_derive!(7, A, B, C, D, E, F, G);
expr_func_derive!(8, A, B, C, D, E, F, G, H);
expr_func_derive!(9, A, B, C, D, E, F, G, H, I);
expr_func_derive!(10, A, B, C, D, E, F, G, H, I, J);
expr_func_derive!(11, A, B, C, D, E, F, G, H, I, J, K);
expr_func_derive!(12, A, B, C, D, E, F, G, H, I, J, K, L);
expr_func_derive!(13, A, B, C, D, E, F, G, H, I, J, K, L, M);
expr_func_derive!(14, A, B, C, D, E, F, G, H, I, J, K, L, M, N);
expr_func_derive!(1, A);
expr_func_derive!(2, A, B);
expr_func_derive!(3, A, B, C);
expr_func_derive!(4, A, B, C, D);
expr_func_derive!(5, A, B, C, D, E);
expr_func_derive!(6, A, B, C, D, E, F);
expr_func_derive!(7, A, B, C, D, E, F, G);
expr_func_derive!(8, A, B, C, D, E, F, G, H);
expr_func_derive!(9, A, B, C, D, E, F, G, H, I);
expr_func_derive!(10, A, B, C, D, E, F, G, H, I, J);
expr_func_derive!(11, A, B, C, D, E, F, G, H, I, J, K);
expr_func_derive!(12, A, B, C, D, E, F, G, H, I, J, K, L);
expr_func_derive!(13, A, B, C, D, E, F, G, H, I, J, K, L, M);
expr_func_derive!(14, A, B, C, D, E, F, G, H, I, J, K, L, M, N);
}

View File

@@ -1,6 +1,6 @@
use std::ops::{Range, RangeInclusive};
use orchid_base::error::{mk_err, OrcErr, OrcRes};
use orchid_base::error::{OrcErr, OrcRes, mk_err};
use orchid_base::intern;
use orchid_base::interner::Tok;
use orchid_base::location::Pos;
@@ -11,58 +11,58 @@ use crate::api;
use crate::tree::{GenTok, GenTokTree};
pub fn err_cascade() -> OrcErr {
mk_err(
intern!(str: "An error cascading from a recursive call"),
"This error should not surface. If you are seeing it, something is wrong",
[Pos::None.into()],
)
mk_err(
intern!(str: "An error cascading from a recursive call"),
"This error should not surface. If you are seeing it, something is wrong",
[Pos::None.into()],
)
}
pub fn err_not_applicable() -> OrcErr {
mk_err(
intern!(str: "Pseudo-error to communicate that the current branch in a dispatch doesn't apply"),
&*err_cascade().message,
[Pos::None.into()],
)
mk_err(
intern!(str: "Pseudo-error to communicate that the current branch in a dispatch doesn't apply"),
&*err_cascade().message,
[Pos::None.into()],
)
}
pub struct LexContext<'a> {
pub text: &'a Tok<String>,
pub sys: api::SysId,
pub id: api::ParsId,
pub pos: u32,
pub reqnot: ReqNot<api::ExtMsgSet>,
pub text: &'a Tok<String>,
pub sys: api::SysId,
pub id: api::ParsId,
pub pos: u32,
pub reqnot: ReqNot<api::ExtMsgSet>,
}
impl<'a> LexContext<'a> {
pub fn recurse(&self, tail: &'a str) -> OrcRes<(&'a str, GenTokTree<'a>)> {
let start = self.pos(tail);
let lx =
self.reqnot.request(api::SubLex { pos: start, id: self.id }).ok_or_else(err_cascade)?;
Ok((&self.text[lx.pos as usize..], GenTok::Slot(TokHandle::new(lx.ticket)).at(start..lx.pos)))
}
pub fn recurse(&self, tail: &'a str) -> OrcRes<(&'a str, GenTokTree<'a>)> {
let start = self.pos(tail);
let lx =
self.reqnot.request(api::SubLex { pos: start, id: self.id }).ok_or_else(err_cascade)?;
Ok((&self.text[lx.pos as usize..], GenTok::Slot(TokHandle::new(lx.ticket)).at(start..lx.pos)))
}
pub fn pos(&self, tail: &'a str) -> u32 { (self.text.len() - tail.len()) as u32 }
pub fn pos(&self, tail: &'a str) -> u32 { (self.text.len() - tail.len()) as u32 }
pub fn tok_ran(&self, len: u32, tail: &'a str) -> Range<u32> {
self.pos(tail) - len..self.pos(tail)
}
pub fn tok_ran(&self, len: u32, tail: &'a str) -> Range<u32> {
self.pos(tail) - len..self.pos(tail)
}
}
pub trait Lexer: Send + Sync + Sized + Default + 'static {
const CHAR_FILTER: &'static [RangeInclusive<char>];
fn lex<'a>(tail: &'a str, ctx: &'a LexContext<'a>) -> OrcRes<(&'a str, GenTokTree<'a>)>;
const CHAR_FILTER: &'static [RangeInclusive<char>];
fn lex<'a>(tail: &'a str, ctx: &'a LexContext<'a>) -> OrcRes<(&'a str, GenTokTree<'a>)>;
}
pub trait DynLexer: Send + Sync + 'static {
fn char_filter(&self) -> &'static [RangeInclusive<char>];
fn lex<'a>(&self, tail: &'a str, ctx: &'a LexContext<'a>) -> OrcRes<(&'a str, GenTokTree<'a>)>;
fn char_filter(&self) -> &'static [RangeInclusive<char>];
fn lex<'a>(&self, tail: &'a str, ctx: &'a LexContext<'a>) -> OrcRes<(&'a str, GenTokTree<'a>)>;
}
impl<T: Lexer> DynLexer for T {
fn char_filter(&self) -> &'static [RangeInclusive<char>] { T::CHAR_FILTER }
fn lex<'a>(&self, tail: &'a str, ctx: &'a LexContext<'a>) -> OrcRes<(&'a str, GenTokTree<'a>)> {
T::lex(tail, ctx)
}
fn char_filter(&self) -> &'static [RangeInclusive<char>] { T::CHAR_FILTER }
fn lex<'a>(&self, tail: &'a str, ctx: &'a LexContext<'a>) -> OrcRes<(&'a str, GenTokTree<'a>)> {
T::lex(tail, ctx)
}
}
pub type LexerObj = &'static dyn DynLexer;

View File

@@ -9,10 +9,10 @@ pub mod expr;
pub mod fs;
pub mod func_atom;
pub mod lexer;
pub mod macros;
pub mod msg;
pub mod other_system;
pub mod parser;
pub mod system;
pub mod system_ctor;
pub mod tree;
pub mod macros;

View File

@@ -1,101 +1,111 @@
use std::num::NonZero;
use std::sync::RwLock;
use ahash::HashMap;
use lazy_static::lazy_static;
use never::Never;
use orchid_base::{error::OrcRes, interner::{intern, Tok}, location::Pos, macros::{mtreev_from_api, mtreev_to_api, MTree}, parse::Comment, reqnot::Requester};
use orchid_base::error::OrcRes;
use orchid_base::interner::{Tok, intern};
use orchid_base::location::Pos;
use orchid_base::macros::{MTree, mtreev_from_api, mtreev_to_api};
use orchid_base::parse::Comment;
use orchid_base::reqnot::Requester;
use trait_set::trait_set;
use crate::{api, atom::AtomFactory, lexer::err_cascade, system::SysCtx};
use std::{num::NonZero, sync::RwLock};
use crate::api;
use crate::atom::AtomFactory;
use crate::lexer::err_cascade;
use crate::system::SysCtx;
pub trait Macro {
fn pattern() -> MTree<'static, Never>;
fn apply(binds: HashMap<Tok<String>, MTree<'_, Never>>) -> MTree<'_, AtomFactory>;
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>;
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)
}
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,
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 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 |b| match *b {})
};
Ok(mtreev_from_api(
&self.sys.reqnot.request(req).ok_or_else(err_cascade)?,
&mut |_| panic!("Returned atom from Rule recursion")
))
}
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);});
}
pub 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 |b| match *b {}) };
Ok(mtreev_from_api(&self.sys.reqnot.request(req).ok_or_else(err_cascade)?, &mut |_| {
panic!("Returned atom from Rule recursion")
}))
}
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>) -> OrcRes<Vec<MTree<'a, AtomFactory>>> + Send + Sync;
pub trait RuleCB = for<'a> Fn(RuleCtx<'a>) -> OrcRes<Vec<MTree<'a, AtomFactory>>> + Send + Sync;
}
lazy_static!{
static ref RULES: RwLock<HashMap<api::MacroId, Box<dyn RuleCB>>> = RwLock::default();
lazy_static! {
static ref RULES: RwLock<HashMap<api::MacroId, Box<dyn RuleCB>>> = RwLock::default();
}
pub struct Rule {
pub(crate) comments: Vec<Comment>,
pub(crate) pattern: Vec<MTree<'static, Never>>,
pub(crate) id: api::MacroId,
pub(crate) comments: Vec<Comment>,
pub(crate) pattern: Vec<MTree<'static, Never>>,
pub(crate) id: api::MacroId,
}
impl Rule {
pub(crate) fn to_api(&self) -> api::MacroRule {
api::MacroRule {
comments: self.comments.iter().map(|c| c.to_api()).collect(),
location: api::Location::Inherit,
pattern: mtreev_to_api(&self.pattern, &mut |b| match *b {}),
id: self.id,
}
}
pub(crate) fn to_api(&self) -> api::MacroRule {
api::MacroRule {
comments: self.comments.iter().map(|c| c.to_api()).collect(),
location: api::Location::Inherit,
pattern: mtreev_to_api(&self.pattern, &mut |b| match *b {}),
id: self.id,
}
}
}
pub fn rule_cmt<'a>(
cmt: impl IntoIterator<Item = &'a str>,
pattern: Vec<MTree<'static, Never>>,
apply: impl RuleCB + 'static
cmt: impl IntoIterator<Item = &'a str>,
pattern: Vec<MTree<'static, Never>>,
apply: impl RuleCB + 'static,
) -> Rule {
let mut rules = RULES.write().unwrap();
let id = api::MacroId(NonZero::new(rules.len() as u64 + 1).unwrap());
rules.insert(id, Box::new(apply));
let comments = cmt.into_iter().map(|s| Comment { pos: Pos::Inherit, text: intern(s) }).collect();
Rule { comments, pattern, id }
let mut rules = RULES.write().unwrap();
let id = api::MacroId(NonZero::new(rules.len() as u64 + 1).unwrap());
rules.insert(id, Box::new(apply));
let comments = cmt.into_iter().map(|s| Comment { pos: Pos::Inherit, text: intern(s) }).collect();
Rule { comments, pattern, id }
}
pub fn rule(pattern: Vec<MTree<'static, Never>>, apply: impl RuleCB + 'static) -> Rule {
rule_cmt([], pattern, apply)
rule_cmt([], pattern, apply)
}
pub(crate) fn apply_rule(
id: api::MacroId,
ctx: RuleCtx<'static>
id: api::MacroId,
ctx: RuleCtx<'static>,
) -> OrcRes<Vec<MTree<'static, AtomFactory>>> {
let rules = RULES.read().unwrap();
rules[&id](ctx)
}
let rules = RULES.read().unwrap();
rules[&id](ctx)
}

View File

@@ -5,32 +5,32 @@ use crate::api;
use crate::system::{DynSystemCard, SystemCard};
pub struct SystemHandle<C: SystemCard> {
pub(crate) _card: PhantomData<C>,
pub(crate) id: api::SysId,
pub(crate) _card: PhantomData<C>,
pub(crate) id: api::SysId,
}
impl<C: SystemCard> SystemHandle<C> {
pub(crate) fn new(id: api::SysId) -> Self { Self { _card: PhantomData, id } }
pub fn id(&self) -> api::SysId { self.id }
pub(crate) fn new(id: api::SysId) -> Self { Self { _card: PhantomData, id } }
pub fn id(&self) -> api::SysId { self.id }
}
impl<C: SystemCard> Clone for SystemHandle<C> {
fn clone(&self) -> Self { Self::new(self.id) }
fn clone(&self) -> Self { Self::new(self.id) }
}
pub trait DynSystemHandle {
fn id(&self) -> api::SysId;
fn get_card(&self) -> &dyn DynSystemCard;
fn id(&self) -> api::SysId;
fn get_card(&self) -> &dyn DynSystemCard;
}
pub fn leak_card<T: Default>() -> &'static T {
const {
if 0 != size_of::<T>() {
panic!("Attempted to leak positively sized Card. Card types must always be zero-sized");
}
}
Box::leak(Box::default())
const {
if 0 != size_of::<T>() {
panic!("Attempted to leak positively sized Card. Card types must always be zero-sized");
}
}
Box::leak(Box::default())
}
impl<C: SystemCard> DynSystemHandle for SystemHandle<C> {
fn id(&self) -> api::SysId { self.id }
fn get_card(&self) -> &'static dyn DynSystemCard { leak_card::<C>() }
fn id(&self) -> api::SysId { self.id }
fn get_card(&self) -> &'static dyn DynSystemCard { leak_card::<C>() }
}

View File

@@ -7,34 +7,34 @@ use crate::tree::GenTokTree;
pub type GenSnippet<'a> = Snippet<'a, 'a, ForeignAtom<'a>, AtomFactory>;
pub trait Parser: Send + Sync + Sized + Default + 'static {
const LINE_HEAD: &'static str;
fn parse(
exported: bool,
comments: Vec<Comment>,
line: GenSnippet<'_>,
) -> OrcRes<Vec<GenTokTree<'_>>>;
const LINE_HEAD: &'static str;
fn parse(
exported: bool,
comments: Vec<Comment>,
line: GenSnippet<'_>,
) -> OrcRes<Vec<GenTokTree<'_>>>;
}
pub trait DynParser: Send + Sync + 'static {
fn line_head(&self) -> &'static str;
fn parse<'a>(
&self,
exported: bool,
comments: Vec<Comment>,
line: GenSnippet<'a>,
) -> OrcRes<Vec<GenTokTree<'a>>>;
fn line_head(&self) -> &'static str;
fn parse<'a>(
&self,
exported: bool,
comments: Vec<Comment>,
line: GenSnippet<'a>,
) -> OrcRes<Vec<GenTokTree<'a>>>;
}
impl<T: Parser> DynParser for T {
fn line_head(&self) -> &'static str { Self::LINE_HEAD }
fn parse<'a>(
&self,
exported: bool,
comments: Vec<Comment>,
line: GenSnippet<'a>,
) -> OrcRes<Vec<GenTokTree<'a>>> {
Self::parse(exported, comments, line)
}
fn line_head(&self) -> &'static str { Self::LINE_HEAD }
fn parse<'a>(
&self,
exported: bool,
comments: Vec<Comment>,
line: GenSnippet<'a>,
) -> OrcRes<Vec<GenTokTree<'a>>> {
Self::parse(exported, comments, line)
}
}
pub type ParserObj = &'static dyn DynParser;

View File

@@ -10,11 +10,10 @@ use orchid_base::logging::Logger;
use orchid_base::reqnot::{Receipt, ReqNot};
use crate::api;
use crate::atom::{get_info, AtomCtx, AtomDynfo, AtomicFeatures, ForeignAtom, TypAtom};
use crate::atom::{AtomCtx, AtomDynfo, AtomicFeatures, ForeignAtom, TypAtom, get_info};
use crate::entrypoint::ExtReq;
use crate::fs::DeclFs;
use crate::func_atom::Fun;
// use crate::fun::Fun;
use crate::lexer::LexerObj;
use crate::parser::ParserObj;
use crate::system_ctor::{CtedObj, SystemCtor};
@@ -22,118 +21,115 @@ use crate::tree::MemKind;
/// System as consumed by foreign code
pub trait SystemCard: Default + Send + Sync + 'static {
type Ctor: SystemCtor;
type Req: Coding;
fn atoms() -> impl IntoIterator<Item = Option<Box<dyn AtomDynfo>>>;
type Ctor: SystemCtor;
type Req: Coding;
fn atoms() -> impl IntoIterator<Item = Option<Box<dyn AtomDynfo>>>;
}
pub trait DynSystemCard: Send + Sync + 'static {
fn name(&self) -> &'static str;
/// Atoms explicitly defined by the system card. Do not rely on this for
/// querying atoms as it doesn't include the general atom types
fn atoms(&self) -> BoxedIter<Option<Box<dyn AtomDynfo>>>;
fn name(&self) -> &'static str;
/// Atoms explicitly defined by the system card. Do not rely on this for
/// querying atoms as it doesn't include the general atom types
fn atoms(&self) -> BoxedIter<Option<Box<dyn AtomDynfo>>>;
}
/// Atoms supported by this package which may appear in all extensions.
/// The indices of these are bitwise negated, such that the MSB of an atom index
/// marks whether it belongs to this package (0) or the importer (1)
fn general_atoms() -> impl Iterator<Item = Option<Box<dyn AtomDynfo>>> {
[Some(Fun::dynfo())].into_iter()
[Some(Fun::dynfo())].into_iter()
}
pub fn atom_info_for(
sys: &(impl DynSystemCard + ?Sized),
tid: TypeId,
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)))
.find(|ent| ent.1.tid() == tid)
(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)))
.find(|ent| ent.1.tid() == tid)
}
pub fn atom_by_idx(
sys: &(impl DynSystemCard + ?Sized),
tid: api::AtomId,
sys: &(impl DynSystemCard + ?Sized),
tid: api::AtomId,
) -> Option<Box<dyn AtomDynfo>> {
if (u64::from(tid.0) >> (u64::BITS - 1)) & 1 == 1 {
general_atoms().nth(!u64::from(tid.0) as usize).unwrap()
} else {
sys.atoms().nth(u64::from(tid.0) as usize - 1).unwrap()
}
if (u64::from(tid.0) >> (u64::BITS - 1)) & 1 == 1 {
general_atoms().nth(!u64::from(tid.0) as usize).unwrap()
} else {
sys.atoms().nth(u64::from(tid.0) as usize - 1).unwrap()
}
}
pub fn resolv_atom(
sys: &(impl DynSystemCard + ?Sized),
atom: &api::Atom,
) -> Box<dyn AtomDynfo> {
let tid = api::AtomId::decode(&mut &atom.data[..8]);
atom_by_idx(sys, tid).expect("Value of nonexistent type found")
pub fn resolv_atom(sys: &(impl DynSystemCard + ?Sized), atom: &api::Atom) -> Box<dyn AtomDynfo> {
let tid = api::AtomId::decode(&mut &atom.data[..8]);
atom_by_idx(sys, tid).expect("Value of nonexistent type found")
}
impl<T: SystemCard> DynSystemCard for T {
fn name(&self) -> &'static str { T::Ctor::NAME }
fn atoms(&self) -> BoxedIter<Option<Box<dyn AtomDynfo>>> { Box::new(Self::atoms().into_iter()) }
fn name(&self) -> &'static str { T::Ctor::NAME }
fn atoms(&self) -> BoxedIter<Option<Box<dyn AtomDynfo>>> { Box::new(Self::atoms().into_iter()) }
}
/// System as defined by author
pub trait System: Send + Sync + SystemCard + 'static {
fn env() -> Vec<(Tok<String>, MemKind)>;
fn vfs() -> DeclFs;
fn lexers() -> Vec<LexerObj>;
fn parsers() -> Vec<ParserObj>;
fn request(hand: ExtReq, req: Self::Req) -> Receipt;
fn env() -> Vec<(Tok<String>, MemKind)>;
fn vfs() -> DeclFs;
fn lexers() -> Vec<LexerObj>;
fn parsers() -> Vec<ParserObj>;
fn request(hand: ExtReq, req: Self::Req) -> Receipt;
}
pub trait DynSystem: Send + Sync + DynSystemCard + 'static {
fn dyn_env(&self) -> HashMap<Tok<String>, MemKind>;
fn dyn_vfs(&self) -> DeclFs;
fn dyn_lexers(&self) -> Vec<LexerObj>;
fn dyn_parsers(&self) -> Vec<ParserObj>;
fn dyn_request(&self, hand: ExtReq, req: Vec<u8>) -> Receipt;
fn card(&self) -> &dyn DynSystemCard;
fn dyn_env(&self) -> HashMap<Tok<String>, MemKind>;
fn dyn_vfs(&self) -> DeclFs;
fn dyn_lexers(&self) -> Vec<LexerObj>;
fn dyn_parsers(&self) -> Vec<ParserObj>;
fn dyn_request(&self, hand: ExtReq, req: Vec<u8>) -> Receipt;
fn card(&self) -> &dyn DynSystemCard;
}
impl<T: System> DynSystem for T {
fn dyn_env(&self) -> HashMap<Tok<String>, MemKind> { Self::env().into_iter().collect() }
fn dyn_vfs(&self) -> DeclFs { Self::vfs() }
fn dyn_lexers(&self) -> Vec<LexerObj> { Self::lexers() }
fn dyn_parsers(&self) -> Vec<ParserObj> { Self::parsers() }
fn dyn_request(&self, hand: ExtReq, req: Vec<u8>) -> Receipt {
Self::request(hand, <Self as SystemCard>::Req::decode(&mut &req[..]))
}
fn card(&self) -> &dyn DynSystemCard { self }
fn dyn_env(&self) -> HashMap<Tok<String>, MemKind> { Self::env().into_iter().collect() }
fn dyn_vfs(&self) -> DeclFs { Self::vfs() }
fn dyn_lexers(&self) -> Vec<LexerObj> { Self::lexers() }
fn dyn_parsers(&self) -> Vec<ParserObj> { Self::parsers() }
fn dyn_request(&self, hand: ExtReq, req: Vec<u8>) -> Receipt {
Self::request(hand, <Self as SystemCard>::Req::decode(&mut &req[..]))
}
fn card(&self) -> &dyn DynSystemCard { self }
}
pub fn downcast_atom<A: AtomicFeatures>(foreign: ForeignAtom) -> Result<TypAtom<A>, ForeignAtom> {
let mut data = &foreign.atom.data[..];
let ctx = foreign.ctx.clone();
let info_ent = (ctx.cted.deps().find(|s| s.id() == foreign.atom.owner))
.map(|sys| get_info::<A>(sys.get_card()))
.filter(|(pos, _)| api::AtomId::decode(&mut data) == *pos);
match info_ent {
None => Err(foreign),
Some((_, info)) => {
let val = info.decode(AtomCtx(data, foreign.atom.drop, ctx));
let value = *val.downcast::<A::Data>().expect("atom decode returned wrong type");
Ok(TypAtom { value, data: foreign })
},
}
let mut data = &foreign.atom.data[..];
let ctx = foreign.ctx.clone();
let info_ent = (ctx.cted.deps().find(|s| s.id() == foreign.atom.owner))
.map(|sys| get_info::<A>(sys.get_card()))
.filter(|(pos, _)| api::AtomId::decode(&mut data) == *pos);
match info_ent {
None => Err(foreign),
Some((_, info)) => {
let val = info.decode(AtomCtx(data, foreign.atom.drop, ctx));
let value = *val.downcast::<A::Data>().expect("atom decode returned wrong type");
Ok(TypAtom { value, data: foreign })
},
}
}
#[derive(Clone)]
pub struct SysCtx {
pub reqnot: ReqNot<api::ExtMsgSet>,
pub id: api::SysId,
pub cted: CtedObj,
pub logger: Arc<Logger>,
pub reqnot: ReqNot<api::ExtMsgSet>,
pub id: api::SysId,
pub cted: CtedObj,
pub logger: Arc<Logger>,
}
impl SysCtx {
pub fn new(
id: api::SysId,
cted: &CtedObj,
logger: &Arc<Logger>,
reqnot: ReqNot<api::ExtMsgSet>,
) -> Self {
Self { cted: cted.clone(), id, logger: logger.clone(), reqnot }
}
pub fn new(
id: api::SysId,
cted: &CtedObj,
logger: &Arc<Logger>,
reqnot: ReqNot<api::ExtMsgSet>,
) -> Self {
Self { cted: cted.clone(), id, logger: logger.clone(), reqnot }
}
}

View File

@@ -1,7 +1,7 @@
use std::any::Any;
use std::sync::Arc;
use orchid_base::boxed_iter::{box_empty, box_once, BoxedIter};
use orchid_base::boxed_iter::{BoxedIter, box_empty, box_once};
use ordered_float::NotNan;
use crate::api;
@@ -9,94 +9,94 @@ use crate::other_system::{DynSystemHandle, SystemHandle};
use crate::system::{DynSystem, System, SystemCard};
pub struct Cted<Ctor: SystemCtor + ?Sized> {
pub deps: <Ctor::Deps as DepDef>::Sat,
pub inst: Arc<Ctor::Instance>,
pub deps: <Ctor::Deps as DepDef>::Sat,
pub inst: Arc<Ctor::Instance>,
}
impl<C: SystemCtor + ?Sized> Clone for Cted<C> {
fn clone(&self) -> Self { Self { deps: self.deps.clone(), inst: self.inst.clone() } }
fn clone(&self) -> Self { Self { deps: self.deps.clone(), inst: self.inst.clone() } }
}
pub trait DynCted: Send + Sync + 'static {
fn as_any(&self) -> &dyn Any;
fn deps<'a>(&'a self) -> BoxedIter<'a, &'a (dyn DynSystemHandle + 'a)>;
fn inst(&self) -> Arc<dyn DynSystem>;
fn as_any(&self) -> &dyn Any;
fn deps<'a>(&'a self) -> BoxedIter<'a, &'a (dyn DynSystemHandle + 'a)>;
fn inst(&self) -> Arc<dyn DynSystem>;
}
impl<C: SystemCtor + ?Sized> DynCted for Cted<C> {
fn as_any(&self) -> &dyn Any { self }
fn deps<'a>(&'a self) -> BoxedIter<'a, &'a (dyn DynSystemHandle + 'a)> { self.deps.iter() }
fn inst(&self) -> Arc<dyn DynSystem> { self.inst.clone() }
fn as_any(&self) -> &dyn Any { self }
fn deps<'a>(&'a self) -> BoxedIter<'a, &'a (dyn DynSystemHandle + 'a)> { self.deps.iter() }
fn inst(&self) -> Arc<dyn DynSystem> { self.inst.clone() }
}
pub type CtedObj = Arc<dyn DynCted>;
pub trait DepSat: Clone + Send + Sync + 'static {
fn iter<'a>(&'a self) -> BoxedIter<'a, &'a (dyn DynSystemHandle + 'a)>;
fn iter<'a>(&'a self) -> BoxedIter<'a, &'a (dyn DynSystemHandle + 'a)>;
}
pub trait DepDef {
type Sat: DepSat;
fn report(names: &mut impl FnMut(&'static str));
fn create(take: &mut impl FnMut() -> api::SysId) -> Self::Sat;
type Sat: DepSat;
fn report(names: &mut impl FnMut(&'static str));
fn create(take: &mut impl FnMut() -> api::SysId) -> Self::Sat;
}
impl<T: SystemCard> DepSat for SystemHandle<T> {
fn iter<'a>(&'a self) -> BoxedIter<'a, &'a (dyn DynSystemHandle + 'a)> { box_once(self) }
fn iter<'a>(&'a self) -> BoxedIter<'a, &'a (dyn DynSystemHandle + 'a)> { box_once(self) }
}
impl<T: SystemCard> DepDef for T {
type Sat = SystemHandle<Self>;
fn report(names: &mut impl FnMut(&'static str)) { names(T::Ctor::NAME) }
fn create(take: &mut impl FnMut() -> api::SysId) -> Self::Sat { SystemHandle::new(take()) }
type Sat = SystemHandle<Self>;
fn report(names: &mut impl FnMut(&'static str)) { names(T::Ctor::NAME) }
fn create(take: &mut impl FnMut() -> api::SysId) -> Self::Sat { SystemHandle::new(take()) }
}
impl DepSat for () {
fn iter<'a>(&'a self) -> BoxedIter<'a, &'a (dyn DynSystemHandle + 'a)> { box_empty() }
fn iter<'a>(&'a self) -> BoxedIter<'a, &'a (dyn DynSystemHandle + 'a)> { box_empty() }
}
impl DepDef for () {
type Sat = ();
fn create(_: &mut impl FnMut() -> api::SysId) -> Self::Sat {}
fn report(_: &mut impl FnMut(&'static str)) {}
type Sat = ();
fn create(_: &mut impl FnMut() -> api::SysId) -> Self::Sat {}
fn report(_: &mut impl FnMut(&'static str)) {}
}
pub trait SystemCtor: Send + Sync + 'static {
type Deps: DepDef;
type Instance: System;
const NAME: &'static str;
const VERSION: f64;
fn inst() -> Option<Self::Instance>;
type Deps: DepDef;
type Instance: System;
const NAME: &'static str;
const VERSION: f64;
fn inst() -> Option<Self::Instance>;
}
pub trait DynSystemCtor: Send + Sync + 'static {
fn decl(&self, id: api::SysDeclId) -> api::SystemDecl;
fn new_system(&self, new: &api::NewSystem) -> CtedObj;
fn decl(&self, id: api::SysDeclId) -> api::SystemDecl;
fn new_system(&self, new: &api::NewSystem) -> CtedObj;
}
impl<T: SystemCtor> DynSystemCtor for T {
fn decl(&self, id: api::SysDeclId) -> api::SystemDecl {
// Version is equivalent to priority for all practical purposes
let priority = NotNan::new(T::VERSION).unwrap();
// aggregate depends names
let mut depends = Vec::new();
T::Deps::report(&mut |n| depends.push(n.to_string()));
api::SystemDecl { name: T::NAME.to_string(), depends, id, priority }
}
fn new_system(&self, api::NewSystem { system: _, id: _, depends }: &api::NewSystem) -> CtedObj {
let mut ids = depends.iter().copied();
let inst = Arc::new(T::inst().expect("Constructor did not create system"));
let deps = T::Deps::create(&mut || ids.next().unwrap());
Arc::new(Cted::<T> { deps, inst })
}
fn decl(&self, id: api::SysDeclId) -> api::SystemDecl {
// Version is equivalent to priority for all practical purposes
let priority = NotNan::new(T::VERSION).unwrap();
// aggregate depends names
let mut depends = Vec::new();
T::Deps::report(&mut |n| depends.push(n.to_string()));
api::SystemDecl { name: T::NAME.to_string(), depends, id, priority }
}
fn new_system(&self, api::NewSystem { system: _, id: _, depends }: &api::NewSystem) -> CtedObj {
let mut ids = depends.iter().copied();
let inst = Arc::new(T::inst().expect("Constructor did not create system"));
let deps = T::Deps::create(&mut || ids.next().unwrap());
Arc::new(Cted::<T> { deps, inst })
}
}
mod dep_set_tuple_impls {
use orchid_base::box_chain;
use orchid_base::boxed_iter::BoxedIter;
use paste::paste;
use orchid_base::box_chain;
use orchid_base::boxed_iter::BoxedIter;
use paste::paste;
use super::{DepDef, DepSat};
use crate::api;
use crate::system_ctor::DynSystemHandle;
use super::{DepDef, DepSat};
use crate::api;
use crate::system_ctor::DynSystemHandle;
macro_rules! dep_set_tuple_impl {
macro_rules! dep_set_tuple_impl {
($($name:ident),*) => {
impl<$( $name :DepSat ),*> DepSat for ( $( $name , )* ) {
fn iter<'a>(&'a self) -> BoxedIter<'a, &'a (dyn DynSystemHandle + 'a)> {
@@ -137,20 +137,20 @@ mod dep_set_tuple_impls {
};
}
dep_set_tuple_impl!(A);
dep_set_tuple_impl!(A, B); // 2
dep_set_tuple_impl!(A, B, C);
dep_set_tuple_impl!(A, B, C, D); // 4
dep_set_tuple_impl!(A, B, C, D, E);
dep_set_tuple_impl!(A, B, C, D, E, F);
dep_set_tuple_impl!(A, B, C, D, E, F, G);
dep_set_tuple_impl!(A, B, C, D, E, F, G, H); // 8
dep_set_tuple_impl!(A, B, C, D, E, F, G, H, I);
dep_set_tuple_impl!(A, B, C, D, E, F, G, H, I, J);
dep_set_tuple_impl!(A, B, C, D, E, F, G, H, I, J, K);
dep_set_tuple_impl!(A, B, C, D, E, F, G, H, I, J, K, L); // 12
dep_set_tuple_impl!(A, B, C, D, E, F, G, H, I, J, K, L, M);
dep_set_tuple_impl!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
dep_set_tuple_impl!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
dep_set_tuple_impl!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P); // 16
dep_set_tuple_impl!(A);
dep_set_tuple_impl!(A, B); // 2
dep_set_tuple_impl!(A, B, C);
dep_set_tuple_impl!(A, B, C, D); // 4
dep_set_tuple_impl!(A, B, C, D, E);
dep_set_tuple_impl!(A, B, C, D, E, F);
dep_set_tuple_impl!(A, B, C, D, E, F, G);
dep_set_tuple_impl!(A, B, C, D, E, F, G, H); // 8
dep_set_tuple_impl!(A, B, C, D, E, F, G, H, I);
dep_set_tuple_impl!(A, B, C, D, E, F, G, H, I, J);
dep_set_tuple_impl!(A, B, C, D, E, F, G, H, I, J, K);
dep_set_tuple_impl!(A, B, C, D, E, F, G, H, I, J, K, L); // 12
dep_set_tuple_impl!(A, B, C, D, E, F, G, H, I, J, K, L, M);
dep_set_tuple_impl!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
dep_set_tuple_impl!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
dep_set_tuple_impl!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P); // 16
}

View File

@@ -15,7 +15,7 @@ use trait_set::trait_set;
use crate::api;
use crate::atom::{AtomFactory, ForeignAtom};
use crate::conv::{ToExpr, TryFromExpr};
use crate::conv::ToExpr;
use crate::entrypoint::MemberRecord;
use crate::expr::Expr;
use crate::func_atom::{ExprFunc, Fun};
@@ -26,169 +26,169 @@ pub type GenTokTree<'a> = TokTree<'a, ForeignAtom<'a>, AtomFactory>;
pub type GenTok<'a> = Token<'a, ForeignAtom<'a>, AtomFactory>;
pub fn do_extra(f: &AtomFactory, r: Range<u32>, ctx: SysCtx) -> api::TokenTree {
api::TokenTree { range: r, token: api::Token::Atom(f.clone().build(ctx)) }
api::TokenTree { range: r, token: api::Token::Atom(f.clone().build(ctx)) }
}
fn with_export(mem: GenMember, public: bool) -> Vec<GenItem> {
(public.then(|| GenItemKind::Export(mem.name.clone()).at(Pos::Inherit)).into_iter())
.chain([GenItemKind::Member(mem).at(Pos::Inherit)])
.collect()
(public.then(|| GenItemKind::Export(mem.name.clone()).at(Pos::Inherit)).into_iter())
.chain([GenItemKind::Member(mem).at(Pos::Inherit)])
.collect()
}
pub struct GenItem {
pub kind: GenItemKind,
pub comments: Vec<Comment>,
pub pos: Pos,
pub kind: GenItemKind,
pub comments: Vec<Comment>,
pub pos: Pos,
}
impl GenItem {
pub fn into_api(self, ctx: &mut impl TreeIntoApiCtx) -> api::Item {
let kind = match self.kind {
GenItemKind::Export(n) => api::ItemKind::Export(n.to_api()),
GenItemKind::Member(mem) => api::ItemKind::Member(mem.into_api(ctx)),
GenItemKind::Import(cn) => api::ItemKind::Import(cn.tok().to_api()),
GenItemKind::Macro(prio, rules) => api::ItemKind::Macro(api::MacroBlock {
priority: prio,
rules: rules.into_iter().map(|r| r.to_api()).collect_vec(),
}),
};
let comments = self.comments.into_iter().map(|c| c.to_api()).collect_vec();
api::Item { location: self.pos.to_api(), comments, kind }
}
pub fn into_api(self, ctx: &mut impl TreeIntoApiCtx) -> api::Item {
let kind = match self.kind {
GenItemKind::Export(n) => api::ItemKind::Export(n.to_api()),
GenItemKind::Member(mem) => api::ItemKind::Member(mem.into_api(ctx)),
GenItemKind::Import(cn) => api::ItemKind::Import(cn.tok().to_api()),
GenItemKind::Macro(prio, rules) => api::ItemKind::Macro(api::MacroBlock {
priority: prio,
rules: rules.into_iter().map(|r| r.to_api()).collect_vec(),
}),
};
let comments = self.comments.into_iter().map(|c| c.to_api()).collect_vec();
api::Item { location: self.pos.to_api(), comments, kind }
}
}
pub fn cnst(public: bool, name: &str, value: impl ToExpr) -> Vec<GenItem> {
with_export(GenMember { name: intern(name), kind: MemKind::Const(value.to_expr()) }, public)
with_export(GenMember { name: intern(name), kind: MemKind::Const(value.to_expr()) }, public)
}
pub fn module(
public: bool,
name: &str,
imports: impl IntoIterator<Item = Sym>,
items: impl IntoIterator<Item = Vec<GenItem>>,
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);
with_export(GenMember { name, kind }, public)
let (name, kind) = root_mod(name, imports, items);
with_export(GenMember { name, kind }, public)
}
pub fn root_mod(
name: &str,
imports: impl IntoIterator<Item = Sym>,
items: impl IntoIterator<Item = Vec<GenItem>>,
name: &str,
imports: impl IntoIterator<Item = Sym>,
items: impl IntoIterator<Item = Vec<GenItem>>,
) -> (Tok<String>, MemKind) {
let kind = MemKind::Mod {
imports: imports.into_iter().collect(),
items: items.into_iter().flatten().collect(),
};
(intern(name), kind)
let kind = MemKind::Mod {
imports: imports.into_iter().collect(),
items: items.into_iter().flatten().collect(),
};
(intern(name), kind)
}
pub fn fun<I, O>(exported: bool, name: &str, xf: impl ExprFunc<I, O>) -> Vec<GenItem> {
let fac = LazyMemberFactory::new(move |sym| MemKind::Const(Fun::new(sym, xf).to_expr()));
with_export(GenMember { name: intern(name), kind: MemKind::Lazy(fac) }, exported)
let fac = LazyMemberFactory::new(move |sym| MemKind::Const(Fun::new(sym, xf).to_expr()));
with_export(GenMember { name: intern(name), 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![GenItemKind::Macro(prio, rules.into_iter().collect_vec()).gen()]
let prio = prio.map(|p| NotNan::new(p).unwrap());
vec![GenItemKind::Macro(prio, rules.into_iter().collect_vec()).gen()]
}
pub fn comments<'a>(
cmts: impl IntoIterator<Item = &'a str> + Clone,
mut val: Vec<GenItem>,
cmts: impl IntoIterator<Item = &'a str> + Clone,
mut val: Vec<GenItem>,
) -> Vec<GenItem> {
for v in val.iter_mut() {
v.comments
.extend(cmts.clone().into_iter().map(|c| Comment { text: intern(c), pos: Pos::Inherit }));
}
val
for v in val.iter_mut() {
v.comments
.extend(cmts.clone().into_iter().map(|c| Comment { text: intern(c), pos: Pos::Inherit }));
}
val
}
trait_set! {
trait LazyMemberCallback = FnOnce(Sym) -> MemKind + Send + Sync + DynClone
trait LazyMemberCallback = FnOnce(Sym) -> MemKind + Send + Sync + DynClone
}
pub struct LazyMemberFactory(Box<dyn LazyMemberCallback>);
impl LazyMemberFactory {
pub fn new(cb: impl FnOnce(Sym) -> MemKind + Send + Sync + Clone + 'static) -> Self {
Self(Box::new(cb))
}
pub fn build(self, path: Sym) -> MemKind { (self.0)(path) }
pub fn new(cb: impl FnOnce(Sym) -> MemKind + Send + Sync + Clone + 'static) -> Self {
Self(Box::new(cb))
}
pub fn build(self, path: Sym) -> MemKind { (self.0)(path) }
}
impl Clone for LazyMemberFactory {
fn clone(&self) -> Self { Self(clone_box(&*self.0)) }
fn clone(&self) -> Self { Self(clone_box(&*self.0)) }
}
pub enum GenItemKind {
Member(GenMember),
Export(Tok<String>),
Import(Sym),
Macro(Option<NotNan<f64>>, Vec<Rule>),
Member(GenMember),
Export(Tok<String>),
Import(Sym),
Macro(Option<NotNan<f64>>, Vec<Rule>),
}
impl GenItemKind {
pub fn at(self, pos: Pos) -> GenItem { GenItem { kind: self, comments: vec![], pos } }
pub fn gen(self) -> GenItem { GenItem { kind: self, comments: vec![], pos: Pos::Inherit } }
pub fn gen_equiv(self, comments: Vec<Comment>) -> GenItem {
GenItem { kind: self, comments, pos: Pos::Inherit }
}
pub fn at(self, pos: Pos) -> GenItem { GenItem { kind: self, comments: vec![], pos } }
pub fn gen(self) -> GenItem { GenItem { kind: self, comments: vec![], pos: Pos::Inherit } }
pub fn gen_equiv(self, comments: Vec<Comment>) -> GenItem {
GenItem { kind: self, comments, pos: Pos::Inherit }
}
}
pub struct GenMember {
name: Tok<String>,
kind: MemKind,
name: Tok<String>,
kind: MemKind,
}
impl GenMember {
pub fn into_api(self, ctx: &mut impl TreeIntoApiCtx) -> api::Member {
api::Member {
name: self.name.to_api(),
kind: self.kind.into_api(&mut ctx.push_path(self.name)),
}
}
pub fn into_api(self, ctx: &mut impl TreeIntoApiCtx) -> api::Member {
api::Member {
name: self.name.to_api(),
kind: self.kind.into_api(&mut ctx.push_path(self.name)),
}
}
}
pub enum MemKind {
Const(Expr),
Mod { imports: Vec<Sym>, items: Vec<GenItem> },
Lazy(LazyMemberFactory),
Const(Expr),
Mod { imports: Vec<Sym>, items: Vec<GenItem> },
Lazy(LazyMemberFactory),
}
impl MemKind {
pub fn into_api(self, ctx: &mut impl TreeIntoApiCtx) -> api::MemberKind {
match self {
Self::Lazy(lazy) => api::MemberKind::Lazy(ctx.with_lazy(lazy)),
Self::Const(c) =>
api::MemberKind::Const(c.api_return(ctx.sys(), &mut |_| panic!("Slot found in const tree"))),
Self::Mod { imports, items } => api::MemberKind::Module(api::Module {
items: (imports.into_iter())
.map(|t| GenItemKind::Import(t).gen())
.chain(items)
.map(|i| i.into_api(ctx))
.collect_vec(),
}),
}
}
pub fn into_api(self, ctx: &mut impl TreeIntoApiCtx) -> api::MemberKind {
match self {
Self::Lazy(lazy) => api::MemberKind::Lazy(ctx.with_lazy(lazy)),
Self::Const(c) =>
api::MemberKind::Const(c.api_return(ctx.sys(), &mut |_| panic!("Slot in const tree"))),
Self::Mod { imports, items } => api::MemberKind::Module(api::Module {
items: (imports.into_iter())
.map(|t| GenItemKind::Import(t).gen())
.chain(items)
.map(|i| i.into_api(ctx))
.collect_vec(),
}),
}
}
}
pub trait TreeIntoApiCtx {
fn sys(&self) -> SysCtx;
fn with_lazy(&mut self, fac: LazyMemberFactory) -> api::TreeId;
fn push_path(&mut self, seg: Tok<String>) -> impl TreeIntoApiCtx;
fn sys(&self) -> SysCtx;
fn with_lazy(&mut self, fac: LazyMemberFactory) -> api::TreeId;
fn push_path(&mut self, seg: Tok<String>) -> impl TreeIntoApiCtx;
}
pub struct TIACtxImpl<'a, 'b> {
pub sys: SysCtx,
pub basepath: &'a [Tok<String>],
pub path: Substack<'a, Tok<String>>,
pub lazy: &'b mut HashMap<api::TreeId, MemberRecord>,
pub sys: SysCtx,
pub basepath: &'a [Tok<String>],
pub path: Substack<'a, Tok<String>>,
pub lazy: &'b mut HashMap<api::TreeId, MemberRecord>,
}
impl<'a, 'b> TreeIntoApiCtx for TIACtxImpl<'a, 'b> {
fn sys(&self) -> SysCtx { self.sys.clone() }
fn push_path(&mut self, seg: Tok<String>) -> impl TreeIntoApiCtx {
TIACtxImpl {
sys: self.sys.clone(),
lazy: self.lazy,
basepath: self.basepath,
path: self.path.push(seg),
}
}
fn with_lazy(&mut self, fac: LazyMemberFactory) -> api::TreeId {
let id = api::TreeId(NonZero::new((self.lazy.len() + 2) as u64).unwrap());
let path = Sym::new(self.basepath.iter().cloned().chain(self.path.unreverse())).unwrap();
self.lazy.insert(id, MemberRecord::Gen(path, fac));
id
}
fn sys(&self) -> SysCtx { self.sys.clone() }
fn push_path(&mut self, seg: Tok<String>) -> impl TreeIntoApiCtx {
TIACtxImpl {
sys: self.sys.clone(),
lazy: self.lazy,
basepath: self.basepath,
path: self.path.push(seg),
}
}
fn with_lazy(&mut self, fac: LazyMemberFactory) -> api::TreeId {
let id = api::TreeId(NonZero::new((self.lazy.len() + 2) as u64).unwrap());
let path = Sym::new(self.basepath.iter().cloned().chain(self.path.unreverse())).unwrap();
self.lazy.insert(id, MemberRecord::Gen(path, fac));
id
}
}