forked from Orchid/orchid
Began implementing fully isomorphic macros
Like Rust's Proc macros. Now we have preprocessor recursion to worry about. I also made a cool macro for enums
This commit is contained in:
@@ -3,44 +3,42 @@ use std::fmt;
|
||||
use std::io::{Read, Write};
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::{Deref, Range};
|
||||
use std::sync::OnceLock;
|
||||
use std::sync::{Arc, OnceLock};
|
||||
|
||||
use dyn_clone::{clone_box, DynClone};
|
||||
use never::Never;
|
||||
use orchid_api::ExprTicket;
|
||||
use orchid_api_traits::{enc_vec, Coding, Decode, Request};
|
||||
use orchid_api_traits::{enc_vec, Coding, Decode, Encode, Request};
|
||||
use orchid_base::error::{mk_err, OrcErr, OrcRes};
|
||||
use orchid_base::intern;
|
||||
use orchid_base::location::Pos;
|
||||
use orchid_base::name::Sym;
|
||||
use orchid_base::reqnot::Requester;
|
||||
use orchid_base::tree::AtomInTok;
|
||||
use orchid_base::tree::AtomTok;
|
||||
use trait_set::trait_set;
|
||||
|
||||
use crate::api;
|
||||
// use crate::error::{ProjectError, ProjectResult};
|
||||
use crate::expr::{ExprHandle, GenClause, GenExpr, OwnedExpr};
|
||||
use crate::expr::{Expr, ExprData, ExprHandle, ExprKind};
|
||||
use crate::system::{atom_info_for, downcast_atom, DynSystemCard, SysCtx};
|
||||
|
||||
pub trait AtomCard: 'static + Sized {
|
||||
type Data: Clone + Coding + Sized;
|
||||
type Req: Coding;
|
||||
}
|
||||
|
||||
pub trait AtomicVariant {}
|
||||
pub trait Atomic: 'static + Sized {
|
||||
type Variant: AtomicVariant;
|
||||
type Data: Clone + Coding + Sized;
|
||||
type Req: Coding;
|
||||
fn reg_reqs() -> MethodSet<Self>;
|
||||
}
|
||||
impl<A: Atomic> AtomCard for A {
|
||||
type Data = <Self as Atomic>::Data;
|
||||
type Req = <Self as Atomic>::Req;
|
||||
}
|
||||
|
||||
pub trait AtomicFeatures: Atomic {
|
||||
fn factory(self) -> AtomFactory;
|
||||
type Info: AtomDynfo;
|
||||
const INFO: &'static Self::Info;
|
||||
fn info() -> Self::Info;
|
||||
fn dynfo() -> Box<dyn AtomDynfo>;
|
||||
}
|
||||
pub trait ToAtom {
|
||||
fn to_atom_factory(self) -> AtomFactory;
|
||||
@@ -54,17 +52,18 @@ impl ToAtom for AtomFactory {
|
||||
pub trait AtomicFeaturesImpl<Variant: AtomicVariant> {
|
||||
fn _factory(self) -> AtomFactory;
|
||||
type _Info: AtomDynfo;
|
||||
const _INFO: &'static Self::_Info;
|
||||
fn _info() -> Self::_Info;
|
||||
}
|
||||
impl<A: Atomic + AtomicFeaturesImpl<A::Variant> + ?Sized> AtomicFeatures for A {
|
||||
impl<A: Atomic + AtomicFeaturesImpl<A::Variant>> AtomicFeatures for A {
|
||||
fn factory(self) -> AtomFactory { self._factory() }
|
||||
type Info = <Self as AtomicFeaturesImpl<A::Variant>>::_Info;
|
||||
const INFO: &'static Self::Info = Self::_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),
|
||||
) -> (api::AtomId, &'static dyn AtomDynfo) {
|
||||
) -> (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())
|
||||
})
|
||||
@@ -72,34 +71,47 @@ pub fn get_info<A: AtomCard>(
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ForeignAtom<'a> {
|
||||
pub expr: Option<ExprHandle>,
|
||||
pub char_marker: PhantomData<&'a ()>,
|
||||
pub expr: Option<Arc<ExprHandle>>,
|
||||
pub _life: PhantomData<&'a ()>,
|
||||
pub ctx: SysCtx,
|
||||
pub atom: api::Atom,
|
||||
pub pos: Pos,
|
||||
}
|
||||
impl<'a> ForeignAtom<'a> {
|
||||
pub fn oex_opt(self) -> Option<OwnedExpr> {
|
||||
self.expr.map(|handle| {
|
||||
let gen_expr = GenExpr { pos: self.pos, clause: GenClause::Atom(handle.tk, self.atom) };
|
||||
OwnedExpr { handle, val: OnceLock::from(Box::new(gen_expr)) }
|
||||
})
|
||||
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) -> OwnedExpr { self.oex_opt().unwrap() }
|
||||
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().marker(),
|
||||
enc_vec(&m)
|
||||
))?;
|
||||
Some(M::Response::decode(&mut &rep[..]))
|
||||
}
|
||||
}
|
||||
impl<'a> fmt::Display for ForeignAtom<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}::{:?}", if self.expr.is_some() { "Clause" } else { "Tok" }, self.atom)
|
||||
}
|
||||
}
|
||||
impl<'a> AtomInTok for ForeignAtom<'a> {
|
||||
impl<'a> fmt::Debug for ForeignAtom<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "ForeignAtom({self})") }
|
||||
}
|
||||
impl<'a> AtomTok for ForeignAtom<'a> {
|
||||
type Context = SysCtx;
|
||||
fn from_api(atom: &api::Atom, pos: Range<u32>, ctx: &mut Self::Context) -> Self {
|
||||
Self {
|
||||
atom: atom.clone(),
|
||||
char_marker: PhantomData,
|
||||
_life: PhantomData,
|
||||
ctx: ctx.clone(),
|
||||
expr: None,
|
||||
pos: Pos::Range(pos),
|
||||
@@ -108,7 +120,7 @@ impl<'a> AtomInTok for ForeignAtom<'a> {
|
||||
fn to_api(&self) -> orchid_api::Atom { self.atom.clone() }
|
||||
}
|
||||
|
||||
pub struct NotTypAtom(pub Pos, pub OwnedExpr, pub &'static dyn AtomDynfo);
|
||||
pub struct NotTypAtom(pub Pos, pub Expr, pub Box<dyn AtomDynfo>);
|
||||
impl NotTypAtom {
|
||||
pub fn mk_err(&self) -> OrcErr {
|
||||
mk_err(
|
||||
@@ -119,26 +131,86 @@ impl NotTypAtom {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait AtomMethod: Request {
|
||||
const NAME: &str;
|
||||
}
|
||||
pub trait Supports<M: AtomMethod>: AtomCard {
|
||||
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
|
||||
}
|
||||
|
||||
pub struct AtomReqHandler<A: AtomCard> {
|
||||
key: Sym,
|
||||
cb: Box<dyn AtomReqCb<A>>,
|
||||
}
|
||||
|
||||
pub struct MethodSet<A: AtomCard> {
|
||||
handlers: Vec<AtomReqHandler<A>>,
|
||||
}
|
||||
impl<A: AtomCard> MethodSet<A> {
|
||||
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(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()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct TypAtom<'a, A: AtomicFeatures> {
|
||||
pub data: ForeignAtom<'a>,
|
||||
pub value: A::Data,
|
||||
}
|
||||
impl<A: AtomicFeatures> TypAtom<'static, A> {
|
||||
pub fn downcast(expr: ExprHandle) -> Result<Self, NotTypAtom> {
|
||||
match OwnedExpr::new(expr).foreign_atom() {
|
||||
Err(oe) => Err(NotTypAtom(oe.get_data().pos.clone(), oe, A::INFO)),
|
||||
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(), A::INFO)),
|
||||
Err(fa) => Err(NotTypAtom(fa.pos.clone(), fa.oex(), Box::new(A::info()))),
|
||||
Ok(tatom) => Ok(tatom),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<'a, A: AtomicFeatures> TypAtom<'a, A> {
|
||||
pub fn request<R: Coding + Into<A::Req> + Request>(&self, req: R) -> R::Response {
|
||||
R::Response::decode(
|
||||
&mut &self.data.ctx.reqnot.request(api::Fwd(self.data.atom.clone(), enc_vec(&req)))[..],
|
||||
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().marker(),
|
||||
enc_vec(&req)
|
||||
)).unwrap()[..]
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -153,14 +225,13 @@ 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) -> GenExpr;
|
||||
fn call_ref(&self, ctx: AtomCtx<'_>, arg: api::ExprTicket) -> GenExpr;
|
||||
fn same(&self, ctx: AtomCtx<'_>, other: &api::Atom) -> bool;
|
||||
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<'_>, req: &mut dyn Read, rep: &mut dyn Write);
|
||||
fn command(&self, ctx: AtomCtx<'_>) -> OrcRes<Option<GenExpr>>;
|
||||
fn serialize(&self, ctx: AtomCtx<'_>, write: &mut dyn Write) -> Vec<ExprTicket>;
|
||||
fn deserialize(&self, ctx: SysCtx, data: &[u8], refs: &[ExprTicket]) -> api::Atom;
|
||||
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) -> Vec<api::ExprTicket>;
|
||||
fn deserialize(&self, ctx: SysCtx, data: &[u8], refs: &[api::ExprTicket]) -> api::Atom;
|
||||
fn drop(&self, ctx: AtomCtx<'_>);
|
||||
}
|
||||
|
||||
@@ -177,6 +248,12 @@ impl AtomFactory {
|
||||
impl Clone for AtomFactory {
|
||||
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") }
|
||||
}
|
||||
impl fmt::Display for 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", [])
|
||||
@@ -185,26 +262,3 @@ pub fn err_not_callable() -> OrcErr {
|
||||
pub fn err_not_command() -> OrcErr {
|
||||
mk_err(intern!(str: "This atom is not a command"), "Settled on an inactionable value", [])
|
||||
}
|
||||
|
||||
pub trait ReqPck<T: AtomCard + ?Sized>: Sized {
|
||||
type W: Write + ?Sized;
|
||||
fn unpack<'a>(self) -> (T::Req, &'a mut Self::W, SysCtx)
|
||||
where Self: 'a;
|
||||
fn never(self)
|
||||
where T: AtomCard<Req = Never> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct RequestPack<'a, T: AtomCard + ?Sized, W: Write + ?Sized> {
|
||||
pub req: T::Req,
|
||||
pub write: &'a mut W,
|
||||
pub sys: SysCtx,
|
||||
}
|
||||
|
||||
impl<'a, T: AtomCard + ?Sized, W: Write + ?Sized> ReqPck<T> for RequestPack<'a, T, W> {
|
||||
type W = W;
|
||||
fn unpack<'b>(self) -> (<T as AtomCard>::Req, &'b mut Self::W, SysCtx)
|
||||
where 'a: 'b {
|
||||
(self.req, self.write, self.sys)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
use std::any::{type_name, Any, TypeId};
|
||||
use std::borrow::Cow;
|
||||
use std::io::{Read, Write};
|
||||
use std::marker::PhantomData;
|
||||
use std::sync::Arc;
|
||||
|
||||
use itertools::Itertools;
|
||||
use orchid_api_traits::{enc_vec, Decode, Encode};
|
||||
use orchid_base::error::OrcRes;
|
||||
use orchid_base::id_store::{IdRecord, IdStore};
|
||||
use orchid_base::name::Sym;
|
||||
|
||||
use crate::api;
|
||||
use crate::atom::{
|
||||
err_not_callable, err_not_command, get_info, AtomCard, AtomCtx, AtomDynfo, AtomFactory, Atomic,
|
||||
AtomicFeaturesImpl, AtomicVariant, ReqPck, RequestPack,
|
||||
err_not_callable, err_not_command, get_info, AtomCard, AtomCtx, AtomDynfo, AtomFactory, MethodSet, Atomic, AtomicFeaturesImpl, AtomicVariant,
|
||||
};
|
||||
use crate::expr::{bot, ExprHandle, GenExpr};
|
||||
use crate::expr::{bot, Expr, ExprHandle};
|
||||
use crate::system::SysCtx;
|
||||
|
||||
pub struct OwnedVariant;
|
||||
@@ -28,15 +28,17 @@ impl<A: OwnedAtom + Atomic<Variant = OwnedVariant>> AtomicFeaturesImpl<OwnedVari
|
||||
api::Atom { drop: Some(api::AtomId(rec.id())), data, owner: ctx.id }
|
||||
})
|
||||
}
|
||||
fn _info() -> Self::_Info {
|
||||
OwnedAtomDynfo(A::reg_reqs())
|
||||
}
|
||||
type _Info = OwnedAtomDynfo<A>;
|
||||
const _INFO: &'static Self::_Info = &OwnedAtomDynfo(PhantomData);
|
||||
}
|
||||
|
||||
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)))
|
||||
}
|
||||
|
||||
pub struct OwnedAtomDynfo<T: OwnedAtom>(PhantomData<T>);
|
||||
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))
|
||||
@@ -46,19 +48,18 @@ impl<T: OwnedAtom> AtomDynfo for OwnedAtomDynfo<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) -> GenExpr {
|
||||
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) -> GenExpr {
|
||||
fn call_ref(&self, AtomCtx(_, id, ctx): AtomCtx, arg: api::ExprTicket) -> Expr {
|
||||
with_atom(id.unwrap(), |a| a.dyn_call_ref(ctx, arg))
|
||||
}
|
||||
fn same(&self, AtomCtx(_, id, ctx): AtomCtx, a2: &api::Atom) -> bool {
|
||||
with_atom(id.unwrap(), |a1| with_atom(a2.drop.unwrap(), |a2| a1.dyn_same(ctx, &**a2)))
|
||||
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 handle_req(&self, AtomCtx(_, id, ctx): AtomCtx, req: &mut dyn Read, rep: &mut dyn Write) {
|
||||
with_atom(id.unwrap(), |a| a.dyn_handle_req(ctx, req, rep))
|
||||
}
|
||||
fn command(&self, AtomCtx(_, id, ctx): AtomCtx<'_>) -> OrcRes<Option<GenExpr>> {
|
||||
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) {
|
||||
@@ -71,10 +72,13 @@ impl<T: OwnedAtom> AtomDynfo for OwnedAtomDynfo<T> {
|
||||
) -> Vec<api::ExprTicket> {
|
||||
let id = id.unwrap();
|
||||
id.encode(write);
|
||||
with_atom(id, |a| a.dyn_serialize(ctx, write)).into_iter().map(|t| t.into_tk()).collect_vec()
|
||||
with_atom(id, |a| a.dyn_serialize(ctx, write))
|
||||
.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| ExprHandle::from_args(ctx.clone(), *tk));
|
||||
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)
|
||||
}
|
||||
@@ -100,27 +104,25 @@ impl<'a> DeserializeCtx for DeserCtxImpl<'a> {
|
||||
}
|
||||
|
||||
pub trait RefSet {
|
||||
fn from_iter<I: Iterator<Item = ExprHandle> + ExactSizeIterator>(refs: I) -> Self;
|
||||
fn to_vec(self) -> Vec<ExprHandle>;
|
||||
fn from_iter<I: Iterator<Item = Expr> + ExactSizeIterator>(refs: I) -> Self;
|
||||
fn to_vec(self) -> Vec<Expr>;
|
||||
}
|
||||
|
||||
impl RefSet for () {
|
||||
fn to_vec(self) -> Vec<ExprHandle> { Vec::new() }
|
||||
fn from_iter<I: Iterator<Item = ExprHandle> + ExactSizeIterator>(refs: I) -> Self {
|
||||
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<ExprHandle> {
|
||||
fn from_iter<I: Iterator<Item = ExprHandle> + ExactSizeIterator>(refs: I) -> Self {
|
||||
refs.collect_vec()
|
||||
}
|
||||
fn to_vec(self) -> Vec<ExprHandle> { self }
|
||||
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 }
|
||||
}
|
||||
|
||||
impl<const N: usize> RefSet for [ExprHandle; N] {
|
||||
fn to_vec(self) -> Vec<ExprHandle> { self.into_iter().collect_vec() }
|
||||
fn from_iter<I: Iterator<Item = ExprHandle> + ExactSizeIterator>(refs: I) -> 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!())
|
||||
}
|
||||
@@ -131,22 +133,15 @@ pub trait OwnedAtom: Atomic<Variant = OwnedVariant> + Send + Sync + Any + Clone
|
||||
type Refs: RefSet;
|
||||
fn val(&self) -> Cow<'_, Self::Data>;
|
||||
#[allow(unused_variables)]
|
||||
fn call_ref(&self, arg: ExprHandle) -> GenExpr { bot(err_not_callable()) }
|
||||
fn call(self, arg: ExprHandle) -> GenExpr {
|
||||
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 same(&self, ctx: SysCtx, other: &Self) -> bool {
|
||||
let tname = type_name::<Self>();
|
||||
writeln!(ctx.logger, "Override OwnedAtom::same for {tname} if it can appear in macro input");
|
||||
false
|
||||
}
|
||||
fn handle_req(&self, pck: impl ReqPck<Self>);
|
||||
#[allow(unused_variables)]
|
||||
fn command(self, ctx: SysCtx) -> OrcRes<Option<GenExpr>> { Err(vec![err_not_command()]) }
|
||||
fn command(self, ctx: SysCtx) -> OrcRes<Option<Expr>> { Err(err_not_command().into()) }
|
||||
#[allow(unused_variables)]
|
||||
fn free(self, ctx: SysCtx) {}
|
||||
#[allow(unused_variables)]
|
||||
@@ -159,41 +154,27 @@ 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) -> GenExpr;
|
||||
fn dyn_call(self: Box<Self>, ctx: SysCtx, arg: api::ExprTicket) -> GenExpr;
|
||||
fn dyn_same(&self, ctx: SysCtx, other: &dyn DynOwnedAtom) -> bool;
|
||||
fn dyn_handle_req(&self, ctx: SysCtx, req: &mut dyn Read, rep: &mut dyn Write);
|
||||
fn dyn_command(self: Box<Self>, ctx: SysCtx) -> OrcRes<Option<GenExpr>>;
|
||||
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) -> Vec<ExprHandle>;
|
||||
fn dyn_serialize(&self, ctx: SysCtx, sink: &mut dyn Write) -> 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) -> GenExpr {
|
||||
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) -> GenExpr {
|
||||
fn dyn_call(self: Box<Self>, ctx: SysCtx, arg: api::ExprTicket) -> Expr {
|
||||
self.call(ExprHandle::from_args(ctx, arg))
|
||||
}
|
||||
fn dyn_same(&self, ctx: SysCtx, other: &dyn DynOwnedAtom) -> bool {
|
||||
if TypeId::of::<Self>() != other.as_any_ref().type_id() {
|
||||
return false;
|
||||
}
|
||||
let other_self = other.as_any_ref().downcast_ref().expect("The type_ids are the same");
|
||||
self.same(ctx, other_self)
|
||||
}
|
||||
fn dyn_handle_req(&self, sys: SysCtx, req: &mut dyn Read, write: &mut dyn Write) {
|
||||
let pack =
|
||||
RequestPack::<T, dyn Write> { req: <Self as AtomCard>::Req::decode(req), write, sys };
|
||||
self.handle_req(pack)
|
||||
}
|
||||
fn dyn_command(self: Box<Self>, ctx: SysCtx) -> OrcRes<Option<GenExpr>> { self.command(ctx) }
|
||||
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) -> Vec<ExprHandle> {
|
||||
fn dyn_serialize(&self, ctx: SysCtx, sink: &mut dyn Write) -> Vec<Expr> {
|
||||
self.serialize(ctx, sink).to_vec()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
use std::any::{type_name, Any, TypeId};
|
||||
use std::io::Write;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use orchid_api::ExprTicket;
|
||||
use orchid_api_traits::{enc_vec, Coding, Decode};
|
||||
use orchid_api_traits::{enc_vec, Coding};
|
||||
use orchid_base::error::OrcRes;
|
||||
use orchid_base::name::Sym;
|
||||
|
||||
use crate::api;
|
||||
use crate::atom::{
|
||||
err_not_callable, err_not_command, get_info, AtomCard, AtomCtx, AtomDynfo, AtomFactory, Atomic,
|
||||
AtomicFeaturesImpl, AtomicVariant, ReqPck, RequestPack,
|
||||
err_not_callable, err_not_command, get_info, AtomCard, AtomCtx, AtomDynfo, AtomFactory, MethodSet, Atomic, AtomicFeaturesImpl, AtomicVariant
|
||||
};
|
||||
use crate::expr::{bot, ExprHandle, GenExpr};
|
||||
use crate::expr::{bot, Expr, ExprHandle};
|
||||
use crate::system::SysCtx;
|
||||
|
||||
pub struct ThinVariant;
|
||||
@@ -25,11 +23,13 @@ impl<A: ThinAtom + Atomic<Variant = ThinVariant>> AtomicFeaturesImpl<ThinVariant
|
||||
api::Atom { drop: None, data: buf, owner: ctx.id }
|
||||
})
|
||||
}
|
||||
fn _info() -> Self::_Info {
|
||||
ThinAtomDynfo(Self::reg_reqs())
|
||||
}
|
||||
type _Info = ThinAtomDynfo<Self>;
|
||||
const _INFO: &'static Self::_Info = &ThinAtomDynfo(PhantomData);
|
||||
}
|
||||
|
||||
pub struct ThinAtomDynfo<T: ThinAtom>(PhantomData<T>);
|
||||
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)
|
||||
@@ -37,32 +37,29 @@ impl<T: ThinAtom> AtomDynfo for ThinAtomDynfo<T> {
|
||||
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) -> GenExpr {
|
||||
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) -> GenExpr {
|
||||
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,
|
||||
write: &mut dyn Write,
|
||||
) {
|
||||
let pack = RequestPack::<T, dyn Write> { req: Decode::decode(req), write, sys };
|
||||
T::decode(&mut &buf[..]).handle_req(pack)
|
||||
rep: &mut dyn Write,
|
||||
) -> bool {
|
||||
self.0.dispatch(&T::decode(&mut &buf[..]), sys, key, req, rep)
|
||||
}
|
||||
fn same(&self, AtomCtx(buf, _, ctx): AtomCtx, a2: &api::Atom) -> bool {
|
||||
T::decode(&mut &buf[..]).same(ctx, &T::decode(&mut &a2.data[8..]))
|
||||
}
|
||||
fn command(&self, AtomCtx(buf, _, ctx): AtomCtx<'_>) -> OrcRes<Option<GenExpr>> {
|
||||
fn command(&self, AtomCtx(buf, _, ctx): AtomCtx<'_>) -> OrcRes<Option<Expr>> {
|
||||
T::decode(&mut &buf[..]).command(ctx)
|
||||
}
|
||||
fn serialize(&self, AtomCtx(buf, ..): AtomCtx<'_>, write: &mut dyn Write) -> Vec<ExprTicket> {
|
||||
T::decode(&mut &buf[..]).encode(write);
|
||||
fn serialize(&self, actx: AtomCtx<'_>, write: &mut dyn Write) -> Vec<api::ExprTicket> {
|
||||
T::decode(&mut &actx.0[..]).encode(write);
|
||||
Vec::new()
|
||||
}
|
||||
fn deserialize(&self, ctx: SysCtx, data: &[u8], refs: &[ExprTicket]) -> api::Atom {
|
||||
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)
|
||||
}
|
||||
@@ -76,16 +73,9 @@ pub trait ThinAtom:
|
||||
AtomCard<Data = Self> + Atomic<Variant = ThinVariant> + Coding + Send + Sync + 'static
|
||||
{
|
||||
#[allow(unused_variables)]
|
||||
fn call(&self, arg: ExprHandle) -> GenExpr { bot(err_not_callable()) }
|
||||
fn call(&self, arg: ExprHandle) -> Expr { bot([err_not_callable()]) }
|
||||
#[allow(unused_variables)]
|
||||
fn same(&self, ctx: SysCtx, other: &Self) -> bool {
|
||||
let tname = type_name::<Self>();
|
||||
writeln!(ctx.logger, "Override ThinAtom::same for {tname} if it can appear in macro input");
|
||||
false
|
||||
}
|
||||
fn handle_req(&self, pck: impl ReqPck<Self>);
|
||||
#[allow(unused_variables)]
|
||||
fn command(&self, ctx: SysCtx) -> OrcRes<Option<GenExpr>> { Err(vec![err_not_command()]) }
|
||||
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>()) }
|
||||
}
|
||||
|
||||
@@ -3,19 +3,19 @@ use orchid_base::intern;
|
||||
use orchid_base::location::Pos;
|
||||
|
||||
use crate::atom::{AtomicFeatures, ToAtom, TypAtom};
|
||||
use crate::expr::{atom, botv, ExprHandle, GenExpr, OwnedExpr};
|
||||
use crate::expr::{atom, bot, Expr};
|
||||
use crate::system::downcast_atom;
|
||||
|
||||
pub trait TryFromExpr: Sized {
|
||||
fn try_from_expr(expr: ExprHandle) -> OrcRes<Self>;
|
||||
fn try_from_expr(expr: Expr) -> OrcRes<Self>;
|
||||
}
|
||||
|
||||
impl TryFromExpr for OwnedExpr {
|
||||
fn try_from_expr(expr: ExprHandle) -> OrcRes<Self> { Ok(OwnedExpr::new(expr)) }
|
||||
impl TryFromExpr for 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: ExprHandle) -> OrcRes<Self> {
|
||||
fn try_from_expr(expr: Expr) -> OrcRes<Self> {
|
||||
Ok((T::try_from_expr(expr.clone())?, U::try_from_expr(expr)?))
|
||||
}
|
||||
}
|
||||
@@ -29,31 +29,30 @@ fn err_type(pos: Pos) -> OrcErr {
|
||||
}
|
||||
|
||||
impl<'a, A: AtomicFeatures> TryFromExpr for TypAtom<'a, A> {
|
||||
fn try_from_expr(expr: ExprHandle) -> OrcRes<Self> {
|
||||
OwnedExpr::new(expr)
|
||||
.foreign_atom()
|
||||
.map_err(|ex| vec![err_not_atom(ex.pos.clone())])
|
||||
.and_then(|f| downcast_atom(f).map_err(|f| vec![err_type(f.pos)]))
|
||||
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) -> GenExpr;
|
||||
fn to_expr(self) -> Expr;
|
||||
}
|
||||
|
||||
impl ToExpr for GenExpr {
|
||||
fn to_expr(self) -> GenExpr { self }
|
||||
impl ToExpr for Expr {
|
||||
fn to_expr(self) -> Expr { self }
|
||||
}
|
||||
|
||||
impl<T: ToExpr> ToExpr for OrcRes<T> {
|
||||
fn to_expr(self) -> GenExpr {
|
||||
fn to_expr(self) -> Expr {
|
||||
match self {
|
||||
Err(e) => botv(e),
|
||||
Err(e) => bot(e),
|
||||
Ok(t) => t.to_expr(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: ToAtom> ToExpr for A {
|
||||
fn to_expr(self) -> GenExpr { atom(self) }
|
||||
fn to_expr(self) -> Expr { atom(self) }
|
||||
}
|
||||
|
||||
@@ -6,16 +6,16 @@ use std::{mem, process, thread};
|
||||
|
||||
use hashbrown::HashMap;
|
||||
use itertools::Itertools;
|
||||
use orchid_api::DeserAtom;
|
||||
use orchid_api::ExtMsgSet;
|
||||
use orchid_api_traits::{enc_vec, Decode, Encode};
|
||||
use orchid_base::char_filter::{char_filter_match, char_filter_union, mk_char_filter};
|
||||
use orchid_base::clone;
|
||||
use orchid_base::error::errv_to_apiv;
|
||||
use orchid_base::interner::{deintern, 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};
|
||||
use orchid_base::parse::Snippet;
|
||||
use orchid_base::reqnot::{ReqNot, Requester};
|
||||
use orchid_base::parse::{Comment, Snippet};
|
||||
use orchid_base::reqnot::{ReqHandlish, ReqNot, RequestHandle, Requester};
|
||||
use orchid_base::tree::{ttv_from_api, ttv_to_api};
|
||||
use substack::Substack;
|
||||
|
||||
@@ -23,12 +23,16 @@ use crate::api;
|
||||
use crate::atom::{AtomCtx, AtomDynfo};
|
||||
use crate::atom_owned::OBJ_STORE;
|
||||
use crate::fs::VirtFS;
|
||||
use crate::lexer::{err_cascade, err_lexer_na, LexContext};
|
||||
use crate::lexer::{err_cascade, err_not_applicable, LexContext};
|
||||
use crate::macros::{apply_rule, RuleCtx};
|
||||
use crate::msg::{recv_parent_msg, send_parent_msg};
|
||||
use crate::system::{atom_by_idx, SysCtx};
|
||||
use crate::system_ctor::{CtedObj, DynSystemCtor};
|
||||
use crate::tree::{do_extra, GenTok, GenTokTree, LazyMemberFactory, TIACtxImpl};
|
||||
|
||||
pub type ExtReq = RequestHandle<ExtMsgSet>;
|
||||
pub type ExtReqNot = ReqNot<ExtMsgSet>;
|
||||
|
||||
pub struct ExtensionData {
|
||||
pub name: &'static str,
|
||||
pub systems: &'static [&'static dyn DynSystemCtor],
|
||||
@@ -56,7 +60,7 @@ 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(&'static dyn AtomDynfo, SysCtx, api::AtomId, &[u8]) -> T,
|
||||
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);
|
||||
@@ -107,12 +111,12 @@ fn extension_main_logic(data: ExtensionData) {
|
||||
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 |req| match req.req() {
|
||||
api::HostExtReq::Ping(ping@api::Ping) => req.handle(ping, &()),
|
||||
api::HostExtReq::Sweep(sweep@api::Sweep) => req.handle(sweep, &sweep_replica()),
|
||||
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 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());
|
||||
@@ -123,7 +127,7 @@ fn extension_main_logic(data: ExtensionData) {
|
||||
cted: cted.clone(),
|
||||
id: new_sys.id,
|
||||
logger: logger.clone(),
|
||||
reqnot: req.reqnot()
|
||||
reqnot: hand.reqnot()
|
||||
};
|
||||
let mut tia_ctx = TIACtxImpl{
|
||||
lazy: &mut lazy_mems,
|
||||
@@ -140,7 +144,7 @@ fn extension_main_logic(data: ExtensionData) {
|
||||
cted,
|
||||
lazy_members: lazy_mems
|
||||
});
|
||||
req.handle(new_sys, &api::SystemInst {
|
||||
hand.handle(&new_sys, &api::SystemInst {
|
||||
lex_filter,
|
||||
const_root,
|
||||
line_types: vec![]
|
||||
@@ -148,16 +152,16 @@ fn extension_main_logic(data: ExtensionData) {
|
||||
}
|
||||
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 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) {
|
||||
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());
|
||||
req.handle(get_tree, &tree.into_api(&mut TIACtxImpl{
|
||||
sys: SysCtx::new(*sys_id, &sys.cted, &logger, req.reqnot()),
|
||||
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,
|
||||
@@ -165,100 +169,124 @@ fn extension_main_logic(data: ExtensionData) {
|
||||
}
|
||||
api::HostExtReq::VfsReq(api::VfsReq::GetVfs(get_vfs@api::GetVfs(sys_id))) => {
|
||||
let systems_g = systems.lock().unwrap();
|
||||
req.handle(get_vfs, &systems_g[sys_id].declfs)
|
||||
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 api::VfsRead(sys_id, vfs_id, path) = &vfs_read;
|
||||
let systems_g = systems.lock().unwrap();
|
||||
let path = path.iter().map(|t| deintern(*t)).collect_vec();
|
||||
req.handle(vfs_read, &systems_g[sys_id].vfses[vfs_id].load(PathSlice::new(&path)))
|
||||
hand.handle(&vfs_read, &systems_g[sys_id].vfses[vfs_id].load(PathSlice::new(&path)))
|
||||
}
|
||||
api::HostExtReq::ParserReq(api::ParserReq::LexExpr(lex)) => {
|
||||
let api::LexExpr{ sys, text, pos, id } = *lex;
|
||||
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 = deintern(text);
|
||||
let ctx = LexContext { sys, id, pos, reqnot: req.reqnot(), text: &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.iter().any(|e| *e == err_lexer_na()) => continue,
|
||||
Err(e) if e.any(|e| *e == err_not_applicable()) => continue,
|
||||
Err(e) => {
|
||||
let errv = errv_to_apiv(e.iter().filter(|e| **e == err_cascade()));
|
||||
return req.handle(lex, &if errv.is_empty() { None } else { Some(Err(errv))})
|
||||
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, req.reqnot());
|
||||
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 req.handle(lex, &Some(Ok(api::LexedExpr{ pos, expr })))
|
||||
return hand.handle(&lex, &Some(Ok(api::LexedExpr{ pos, expr })))
|
||||
}
|
||||
}
|
||||
}
|
||||
writeln!(logger, "Got notified about n/a character '{trigger_char}'");
|
||||
req.handle(lex, &None)
|
||||
hand.handle(&lex, &None)
|
||||
},
|
||||
api::HostExtReq::ParserReq(api::ParserReq::ParseLine(pline@api::ParseLine{ sys, line })) => {
|
||||
let mut ctx = mk_ctx(*sys, req.reqnot());
|
||||
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(tail) {
|
||||
Err(e) => Err(errv_to_apiv(e.iter())),
|
||||
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())) }
|
||||
})),
|
||||
};
|
||||
req.handle(pline, &o_line)
|
||||
hand.handle(&pline, &o_line)
|
||||
}
|
||||
api::HostExtReq::AtomReq(atom_req) => {
|
||||
let atom = atom_req.get_atom();
|
||||
with_atom_record(&mk_ctx, req.reqnot(), atom, |nfo, ctx, id, buf| {
|
||||
with_atom_record(&mk_ctx, hand.reqnot(), atom, |nfo, ctx, id, buf| {
|
||||
let actx = AtomCtx(buf, atom.drop, ctx.clone());
|
||||
match atom_req {
|
||||
match &atom_req {
|
||||
api::AtomReq::SerializeAtom(ser) => {
|
||||
let mut buf = enc_vec(&id);
|
||||
let refs = nfo.serialize(actx, &mut buf);
|
||||
req.handle(ser, &(buf, refs))
|
||||
hand.handle(ser, &(buf, refs))
|
||||
}
|
||||
api::AtomReq::AtomPrint(print@api::AtomPrint(_)) => req.handle(print, &nfo.print(actx)),
|
||||
api::AtomReq::AtomSame(same@api::AtomSame(_, r)) => {
|
||||
// different systems or different type tags
|
||||
if atom.owner != r.owner || buf != &r.data[..8] {
|
||||
return req.handle(same, &false)
|
||||
}
|
||||
req.handle(same, &nfo.same(actx, r))
|
||||
},
|
||||
api::AtomReq::Fwded(fwded@api::Fwded(_, payload)) => {
|
||||
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();
|
||||
nfo.handle_req(actx, &mut &payload[..], &mut reply);
|
||||
req.handle(fwded, &reply)
|
||||
let some = nfo.handle_req(actx, Sym::deintern(*key), &mut &payload[..], &mut reply);
|
||||
hand.handle(fwded, &some.then_some(reply))
|
||||
}
|
||||
api::AtomReq::CallRef(call@api::CallRef(_, arg))
|
||||
=> req.handle(call, &nfo.call_ref(actx, *arg).to_api(ctx.clone())),
|
||||
api::AtomReq::FinalCall(call@api::FinalCall(_, arg))
|
||||
=> req.handle(call, &nfo.call(actx, *arg).to_api(ctx.clone())),
|
||||
api::AtomReq::Command(cmd@api::Command(_)) => req.handle(cmd, &match nfo.command(actx) {
|
||||
Err(e) => Err(errv_to_apiv(e.iter())),
|
||||
Ok(opt) => Ok(match opt {
|
||||
Some(cont) => api::NextStep::Continue(cont.into_api(ctx.clone())),
|
||||
None => api::NextStep::Halt,
|
||||
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@DeserAtom(sys, buf, refs)) => {
|
||||
api::HostExtReq::DeserAtom(deser) => {
|
||||
let api::DeserAtom(sys, buf, refs) = &deser;
|
||||
let mut read = &mut &buf[..];
|
||||
let ctx = mk_ctx(*sys, req.reqnot());
|
||||
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");
|
||||
req.handle(deser, &nfo.deserialize(ctx.clone(), read, refs))
|
||||
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)| (deintern(k), mtreev_from_api(&v))).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))),
|
||||
})
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
use std::marker::PhantomData;
|
||||
use std::fmt;
|
||||
use std::ops::Deref;
|
||||
use std::sync::OnceLock;
|
||||
use std::sync::{Arc, OnceLock};
|
||||
|
||||
use derive_destructure::destructure;
|
||||
use orchid_base::error::{errv_from_apiv, errv_to_apiv, OrcErr};
|
||||
use orchid_base::interner::{deintern, Tok};
|
||||
use orchid_api::InspectedKind;
|
||||
use orchid_base::error::{OrcErr, OrcErrv};
|
||||
use orchid_base::interner::Tok;
|
||||
use orchid_base::location::Pos;
|
||||
use orchid_base::reqnot::Requester;
|
||||
|
||||
@@ -19,12 +20,13 @@ pub struct ExprHandle {
|
||||
}
|
||||
impl ExprHandle {
|
||||
pub(crate) fn from_args(ctx: SysCtx, tk: api::ExprTicket) -> Self { Self { ctx, tk } }
|
||||
pub(crate) fn into_tk(self) -> api::ExprTicket {
|
||||
let (tk, ..) = self.destructure();
|
||||
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)
|
||||
}
|
||||
}
|
||||
impl Clone for ExprHandle {
|
||||
fn clone(&self) -> Self {
|
||||
self.ctx.reqnot.notify(api::Acquire(self.ctx.id, self.tk));
|
||||
@@ -35,144 +37,128 @@ impl Drop for ExprHandle {
|
||||
fn drop(&mut self) { self.ctx.reqnot.notify(api::Release(self.ctx.id, self.tk)) }
|
||||
}
|
||||
|
||||
#[derive(Clone, destructure)]
|
||||
pub struct OwnedExpr {
|
||||
pub handle: ExprHandle,
|
||||
pub val: OnceLock<Box<GenExpr>>,
|
||||
#[derive(Clone, Debug, destructure)]
|
||||
pub struct Expr {
|
||||
pub handle: Option<Arc<ExprHandle>>,
|
||||
pub val: OnceLock<ExprData>,
|
||||
}
|
||||
impl OwnedExpr {
|
||||
pub fn new(handle: ExprHandle) -> Self { Self { handle, val: OnceLock::new() } }
|
||||
pub fn get_data(&self) -> &GenExpr {
|
||||
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(|| {
|
||||
Box::new(GenExpr::from_api(
|
||||
self.handle.ctx.reqnot.request(api::Inspect(self.handle.tk)).expr,
|
||||
&self.handle.ctx,
|
||||
))
|
||||
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 {
|
||||
InspectedKind::Atom(a) => ExprKind::Atom(ForeignAtom::new(handle.clone(), a, pos.clone())),
|
||||
InspectedKind::Bottom(b) => ExprKind::Bottom(OrcErrv::from_api(&b)),
|
||||
InspectedKind::Opaque => ExprKind::Opaque,
|
||||
};
|
||||
ExprData { pos, kind }
|
||||
})
|
||||
}
|
||||
pub fn foreign_atom(self) -> Result<ForeignAtom<'static>, Self> {
|
||||
if let GenExpr { clause: GenClause::Atom(_, atom), pos: position } = self.get_data() {
|
||||
let (atom, position) = (atom.clone(), position.clone());
|
||||
return Ok(ForeignAtom {
|
||||
ctx: self.handle.ctx.clone(),
|
||||
expr: Some(self.handle),
|
||||
char_marker: PhantomData,
|
||||
pos: position,
|
||||
atom,
|
||||
});
|
||||
match (self.get_data(), &self.handle) {
|
||||
(ExprData { kind: ExprKind::Atom(atom), .. }, Some(_)) => Ok(atom.clone()),
|
||||
_ => Err(self),
|
||||
}
|
||||
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 OwnedExpr {
|
||||
type Target = GenExpr;
|
||||
impl Deref for Expr {
|
||||
type Target = ExprData;
|
||||
fn deref(&self) -> &Self::Target { self.get_data() }
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct GenExpr {
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ExprData {
|
||||
pub pos: Pos,
|
||||
pub clause: GenClause,
|
||||
pub kind: ExprKind,
|
||||
}
|
||||
impl GenExpr {
|
||||
pub fn to_api(&self, ctx: SysCtx) -> api::Expr {
|
||||
api::Expr { location: self.pos.to_api(), clause: self.clause.to_api(ctx) }
|
||||
}
|
||||
pub fn into_api(self, ctx: SysCtx) -> api::Expr {
|
||||
api::Expr { location: self.pos.to_api(), clause: self.clause.into_api(ctx) }
|
||||
}
|
||||
pub fn from_api(api: api::Expr, ctx: &SysCtx) -> Self {
|
||||
Self { pos: Pos::from_api(&api.location), clause: GenClause::from_api(api.clause, ctx) }
|
||||
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) }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum GenClause {
|
||||
Call(Box<GenExpr>, Box<GenExpr>),
|
||||
Lambda(u64, Box<GenExpr>),
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ExprKind {
|
||||
Call(Box<Expr>, Box<Expr>),
|
||||
Lambda(u64, Box<Expr>),
|
||||
Arg(u64),
|
||||
Slot(OwnedExpr),
|
||||
Seq(Box<GenExpr>, Box<GenExpr>),
|
||||
Seq(Box<Expr>, Box<Expr>),
|
||||
Const(Tok<Vec<Tok<String>>>),
|
||||
NewAtom(AtomFactory),
|
||||
Atom(api::ExprTicket, api::Atom),
|
||||
Bottom(Vec<OrcErr>),
|
||||
Atom(ForeignAtom<'static>),
|
||||
Bottom(OrcErrv),
|
||||
Opaque,
|
||||
}
|
||||
impl GenClause {
|
||||
pub fn to_api(&self, ctx: SysCtx) -> api::Clause {
|
||||
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) =>
|
||||
api::Clause::Call(Box::new(f.to_api(ctx.clone())), Box::new(x.to_api(ctx))),
|
||||
Self::Seq(a, b) => api::Clause::Seq(Box::new(a.to_api(ctx.clone())), Box::new(b.to_api(ctx))),
|
||||
Self::Lambda(arg, body) => api::Clause::Lambda(*arg, Box::new(body.to_api(ctx))),
|
||||
Self::Arg(arg) => api::Clause::Arg(*arg),
|
||||
Self::Const(name) => api::Clause::Const(name.marker()),
|
||||
Self::Bottom(err) => api::Clause::Bottom(errv_to_apiv(err)),
|
||||
Self::NewAtom(fac) => api::Clause::NewAtom(fac.clone().build(ctx)),
|
||||
Self::Atom(tk, atom) => api::Clause::Atom(*tk, atom.clone()),
|
||||
Self::Slot(_) => panic!("Slot is forbidden in const tree"),
|
||||
}
|
||||
}
|
||||
pub fn into_api(self, ctx: SysCtx) -> api::Clause {
|
||||
match self {
|
||||
Self::Call(f, x) =>
|
||||
api::Clause::Call(Box::new(f.into_api(ctx.clone())), Box::new(x.into_api(ctx))),
|
||||
K::Call(Box::new(f.api_return(ctx.clone(), do_slot)), Box::new(x.api_return(ctx, do_slot))),
|
||||
Self::Seq(a, b) =>
|
||||
api::Clause::Seq(Box::new(a.into_api(ctx.clone())), Box::new(b.into_api(ctx))),
|
||||
Self::Lambda(arg, body) => api::Clause::Lambda(arg, Box::new(body.into_api(ctx))),
|
||||
Self::Arg(arg) => api::Clause::Arg(arg),
|
||||
Self::Slot(extk) => api::Clause::Slot(extk.handle.into_tk()),
|
||||
Self::Const(name) => api::Clause::Const(name.marker()),
|
||||
Self::Bottom(err) => api::Clause::Bottom(errv_to_apiv(err.iter())),
|
||||
Self::NewAtom(fac) => api::Clause::NewAtom(fac.clone().build(ctx)),
|
||||
Self::Atom(tk, atom) => api::Clause::Atom(tk, atom),
|
||||
}
|
||||
}
|
||||
pub fn from_api(api: api::Clause, ctx: &SysCtx) -> Self {
|
||||
match api {
|
||||
api::Clause::Arg(id) => Self::Arg(id),
|
||||
api::Clause::Lambda(arg, body) => Self::Lambda(arg, Box::new(GenExpr::from_api(*body, ctx))),
|
||||
api::Clause::NewAtom(_) => panic!("Clause::NewAtom should never be received, only sent"),
|
||||
api::Clause::Bottom(s) => Self::Bottom(errv_from_apiv(&s)),
|
||||
api::Clause::Call(f, x) =>
|
||||
Self::Call(Box::new(GenExpr::from_api(*f, ctx)), Box::new(GenExpr::from_api(*x, ctx))),
|
||||
api::Clause::Seq(a, b) =>
|
||||
Self::Seq(Box::new(GenExpr::from_api(*a, ctx)), Box::new(GenExpr::from_api(*b, ctx))),
|
||||
api::Clause::Const(name) => Self::Const(deintern(name)),
|
||||
api::Clause::Slot(exi) => Self::Slot(OwnedExpr::new(ExprHandle::from_args(ctx.clone(), exi))),
|
||||
api::Clause::Atom(tk, atom) => Self::Atom(tk, atom),
|
||||
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.marker()),
|
||||
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(clause: GenClause) -> GenExpr { GenExpr { pos: Pos::Inherit, clause } }
|
||||
fn inherit(kind: ExprKind) -> Expr { Expr::from_data(ExprData { pos: Pos::Inherit, kind }) }
|
||||
|
||||
pub fn sym_ref(path: Tok<Vec<Tok<String>>>) -> GenExpr { inherit(GenClause::Const(path)) }
|
||||
pub fn atom<A: ToAtom>(atom: A) -> GenExpr { inherit(GenClause::NewAtom(atom.to_atom_factory())) }
|
||||
pub fn sym_ref(path: Tok<Vec<Tok<String>>>) -> Expr { inherit(ExprKind::Const(path)) }
|
||||
pub fn atom<A: ToAtom>(atom: A) -> Expr { inherit(ExprKind::NewAtom(atom.to_atom_factory())) }
|
||||
|
||||
pub fn seq(ops: impl IntoIterator<Item = GenExpr>) -> GenExpr {
|
||||
fn recur(mut ops: impl Iterator<Item = GenExpr>) -> Option<GenExpr> {
|
||||
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(GenClause::Seq(Box::new(op), Box::new(rec))),
|
||||
Some(rec) => inherit(ExprKind::Seq(Box::new(op), Box::new(rec))),
|
||||
})
|
||||
}
|
||||
recur(ops.into_iter()).expect("Empty list provided to seq!")
|
||||
}
|
||||
|
||||
pub fn slot(extk: OwnedExpr) -> GenClause { GenClause::Slot(extk) }
|
||||
pub fn arg(n: u64) -> ExprKind { ExprKind::Arg(n) }
|
||||
|
||||
pub fn arg(n: u64) -> GenClause { GenClause::Arg(n) }
|
||||
|
||||
pub fn lambda(n: u64, b: impl IntoIterator<Item = GenExpr>) -> GenExpr {
|
||||
inherit(GenClause::Lambda(n, Box::new(call(b))))
|
||||
pub fn lambda(n: u64, b: impl IntoIterator<Item = Expr>) -> Expr {
|
||||
inherit(ExprKind::Lambda(n, Box::new(call(b))))
|
||||
}
|
||||
|
||||
pub fn call(v: impl IntoIterator<Item = GenExpr>) -> GenExpr {
|
||||
pub fn call(v: impl IntoIterator<Item = Expr>) -> Expr {
|
||||
v.into_iter()
|
||||
.reduce(|f, x| inherit(GenClause::Call(Box::new(f), Box::new(x))))
|
||||
.reduce(|f, x| inherit(ExprKind::Call(Box::new(f), Box::new(x))))
|
||||
.expect("Empty call expression")
|
||||
}
|
||||
|
||||
pub fn bot(e: OrcErr) -> GenExpr { botv(vec![e]) }
|
||||
pub fn botv(ev: Vec<OrcErr>) -> GenExpr { inherit(GenClause::Bottom(ev)) }
|
||||
pub fn bot(ev: impl IntoIterator<Item = OrcErr>) -> Expr {
|
||||
inherit(ExprKind::Bottom(OrcErrv::new(ev).unwrap()))
|
||||
}
|
||||
|
||||
@@ -5,26 +5,25 @@ use std::sync::{Arc, Mutex};
|
||||
|
||||
use itertools::Itertools;
|
||||
use lazy_static::lazy_static;
|
||||
use never::Never;
|
||||
use orchid_api_traits::Encode;
|
||||
use orchid_base::error::OrcRes;
|
||||
use orchid_base::interner::Tok;
|
||||
use orchid_base::name::Sym;
|
||||
use trait_set::trait_set;
|
||||
|
||||
use crate::atom::{Atomic, ReqPck};
|
||||
use crate::atom::{MethodSet, Atomic};
|
||||
use crate::atom_owned::{DeserializeCtx, OwnedAtom, OwnedVariant};
|
||||
use crate::conv::ToExpr;
|
||||
use crate::expr::{ExprHandle, GenExpr};
|
||||
use crate::expr::{Expr, ExprHandle};
|
||||
use crate::system::SysCtx;
|
||||
|
||||
trait_set! {
|
||||
trait FunCB = Fn(Vec<ExprHandle>) -> OrcRes<GenExpr> + 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<ExprHandle>) -> OrcRes<GenExpr>;
|
||||
fn apply(&self, v: Vec<Expr>) -> OrcRes<Expr>;
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
@@ -34,7 +33,7 @@ lazy_static! {
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct Fun {
|
||||
path: Sym,
|
||||
args: Vec<ExprHandle>,
|
||||
args: Vec<Expr>,
|
||||
arity: u8,
|
||||
fun: Arc<dyn FunCB>,
|
||||
}
|
||||
@@ -53,14 +52,14 @@ impl Fun {
|
||||
}
|
||||
impl Atomic for Fun {
|
||||
type Data = ();
|
||||
type Req = Never;
|
||||
type Variant = OwnedVariant;
|
||||
fn reg_reqs() -> MethodSet<Self> { MethodSet::new() }
|
||||
}
|
||||
impl OwnedAtom for Fun {
|
||||
type Refs = Vec<ExprHandle>;
|
||||
type Refs = Vec<Expr>;
|
||||
fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) }
|
||||
fn call_ref(&self, arg: ExprHandle) -> GenExpr {
|
||||
let new_args = self.args.iter().cloned().chain([arg]).collect_vec();
|
||||
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 {
|
||||
@@ -68,8 +67,7 @@ impl OwnedAtom for Fun {
|
||||
.to_expr()
|
||||
}
|
||||
}
|
||||
fn call(self, arg: ExprHandle) -> GenExpr { self.call_ref(arg) }
|
||||
fn handle_req(&self, pck: impl ReqPck<Self>) { pck.never() }
|
||||
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()
|
||||
@@ -86,7 +84,7 @@ mod expr_func_derives {
|
||||
|
||||
use super::ExprFunc;
|
||||
use crate::conv::{ToExpr, TryFromExpr};
|
||||
use crate::func_atom::{ExprHandle, GenExpr};
|
||||
use crate::func_atom::Expr;
|
||||
|
||||
macro_rules! expr_func_derive {
|
||||
($arity: tt, $($t:ident),*) => {
|
||||
@@ -97,7 +95,7 @@ mod expr_func_derives {
|
||||
Func: Fn($($t,)*) -> Out + Clone + Send + Sync + 'static
|
||||
> ExprFunc<($($t,)*), Out> for Func {
|
||||
const ARITY: u8 = $arity;
|
||||
fn apply(&self, v: Vec<ExprHandle>) -> OrcRes<GenExpr> {
|
||||
fn apply(&self, v: Vec<Expr>) -> OrcRes<Expr> {
|
||||
assert_eq!(v.len(), Self::ARITY.into(), "Arity mismatch");
|
||||
let [$([< $t:lower >],)*] = v.try_into().unwrap_or_else(|_| panic!("Checked above"));
|
||||
Ok(self($($t::try_from_expr([< $t:lower >])?,)*).to_expr())
|
||||
|
||||
@@ -5,22 +5,22 @@ use orchid_base::intern;
|
||||
use orchid_base::interner::Tok;
|
||||
use orchid_base::location::Pos;
|
||||
use orchid_base::reqnot::{ReqNot, Requester};
|
||||
use orchid_base::tree::TreeHandle;
|
||||
use orchid_base::tree::TokHandle;
|
||||
|
||||
use crate::api;
|
||||
use crate::tree::{GenTok, GenTokTree};
|
||||
|
||||
pub fn err_cascade() -> OrcErr {
|
||||
mk_err(
|
||||
intern!(str: "An error cascading from a recursive sublexer"),
|
||||
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_lexer_na() -> OrcErr {
|
||||
pub fn err_not_applicable() -> OrcErr {
|
||||
mk_err(
|
||||
intern!(str: "Pseudo-error to communicate that the lexer doesn't apply"),
|
||||
intern!(str: "Pseudo-error to communicate that the current branch in a dispatch doesn't apply"),
|
||||
&*err_cascade().message,
|
||||
[Pos::None.into()],
|
||||
)
|
||||
@@ -38,7 +38,7 @@ impl<'a> LexContext<'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(TreeHandle::new(lx.ticket)).at(start..lx.pos)))
|
||||
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 }
|
||||
|
||||
@@ -16,3 +16,5 @@ pub mod parser;
|
||||
pub mod system;
|
||||
pub mod system_ctor;
|
||||
pub mod tree;
|
||||
pub mod macros;
|
||||
pub mod api_conv;
|
||||
|
||||
89
orchid-extension/src/macros.rs
Normal file
89
orchid-extension/src/macros.rs
Normal file
@@ -0,0 +1,89 @@
|
||||
use ahash::HashMap;
|
||||
use lazy_static::lazy_static;
|
||||
use orchid_base::{error::OrcRes, interner::{intern, Tok}, location::Pos, macros::{mtreev_from_api, mtreev_to_api, MTree}, parse::Comment, reqnot::Requester};
|
||||
use trait_set::trait_set;
|
||||
use crate::{api, lexer::err_cascade, system::SysCtx};
|
||||
use std::{num::NonZero, sync::RwLock};
|
||||
|
||||
pub trait Macro {
|
||||
fn pattern() -> MTree<'static>;
|
||||
fn apply(binds: HashMap<Tok<String>, MTree<'_>>) -> MTree<'_>;
|
||||
}
|
||||
|
||||
pub trait DynMacro {
|
||||
fn pattern(&self) -> MTree<'static>;
|
||||
fn apply<'a>(&self, binds: HashMap<Tok<String>, MTree<'a>>) -> MTree<'a>;
|
||||
}
|
||||
|
||||
impl<T: Macro> DynMacro for T {
|
||||
fn pattern(&self) -> MTree<'static> { Self::pattern() }
|
||||
fn apply<'a>(&self, binds: HashMap<Tok<String>, MTree<'a>>) -> MTree<'a> { Self::apply(binds) }
|
||||
}
|
||||
|
||||
pub struct RuleCtx<'a> {
|
||||
pub(crate) args: HashMap<Tok<String>, Vec<MTree<'a>>>,
|
||||
pub(crate) run_id: api::ParsId,
|
||||
pub(crate) sys: SysCtx,
|
||||
}
|
||||
impl<'a> RuleCtx<'a> {
|
||||
pub fn recurse(&mut self, tree: &[MTree<'a>]) -> OrcRes<Vec<MTree<'a>>> {
|
||||
let req = api::RunMacros{ run_id: self.run_id, query: mtreev_to_api(tree) };
|
||||
Ok(mtreev_from_api(&self.sys.reqnot.request(req).ok_or_else(err_cascade)?))
|
||||
}
|
||||
pub fn getv(&mut self, key: &Tok<String>) -> Vec<MTree<'a>> {
|
||||
self.args.remove(key).expect("Key not found")
|
||||
}
|
||||
pub fn gets(&mut self, key: &Tok<String>) -> MTree<'a> {
|
||||
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>>> + Send + Sync;
|
||||
}
|
||||
|
||||
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>>,
|
||||
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),
|
||||
id: self.id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rule_cmt<'a>(
|
||||
cmt: impl IntoIterator<Item = &'a str>,
|
||||
pattern: Vec<MTree<'static>>,
|
||||
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 }
|
||||
}
|
||||
|
||||
pub fn rule(pattern: Vec<MTree<'static>>, apply: impl RuleCB + 'static) -> Rule {
|
||||
rule_cmt([], pattern, apply)
|
||||
}
|
||||
|
||||
pub(crate) fn apply_rule(id: api::MacroId, ctx: RuleCtx<'static>) -> OrcRes<Vec<MTree<'static>>> {
|
||||
let rules = RULES.read().unwrap();
|
||||
rules[&id](ctx)
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
use orchid_base::error::OrcRes;
|
||||
use orchid_base::parse::Snippet;
|
||||
use orchid_base::parse::{Comment, Snippet};
|
||||
|
||||
use crate::atom::{AtomFactory, ForeignAtom};
|
||||
use crate::tree::GenTokTree;
|
||||
@@ -8,17 +8,33 @@ 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(line: GenSnippet<'_>) -> OrcRes<Vec<GenTokTree<'_>>>;
|
||||
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, line: GenSnippet<'a>) -> OrcRes<Vec<GenTokTree<'a>>>;
|
||||
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, line: GenSnippet<'a>) -> OrcRes<Vec<GenTokTree<'a>>> { Self::parse(line) }
|
||||
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;
|
||||
|
||||
@@ -3,96 +3,103 @@ use std::num::NonZero;
|
||||
use std::sync::Arc;
|
||||
|
||||
use hashbrown::HashMap;
|
||||
use orchid_api::AtomId;
|
||||
use orchid_api_traits::Decode;
|
||||
use orchid_api_traits::{Coding, Decode};
|
||||
use orchid_base::boxed_iter::BoxedIter;
|
||||
use orchid_base::interner::Tok;
|
||||
use orchid_base::logging::Logger;
|
||||
use orchid_base::reqnot::ReqNot;
|
||||
use orchid_base::reqnot::{Receipt, ReqNot};
|
||||
|
||||
use crate::api;
|
||||
use crate::atom::{get_info, AtomCtx, AtomDynfo, AtomicFeatures, ForeignAtom, TypAtom};
|
||||
use crate::entrypoint::ExtReq;
|
||||
use crate::fs::DeclFs;
|
||||
// use crate::fun::Fun;
|
||||
use crate::lexer::LexerObj;
|
||||
use crate::parser::ParserObj;
|
||||
use crate::system_ctor::{CtedObj, SystemCtor};
|
||||
use crate::tree::GenMemberKind;
|
||||
use crate::tree::MemKind;
|
||||
|
||||
/// System as consumed by foreign code
|
||||
pub trait SystemCard: Default + Send + Sync + 'static {
|
||||
type Ctor: SystemCtor;
|
||||
const ATOM_DEFS: &'static [Option<&'static dyn AtomDynfo>];
|
||||
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) -> &'static [Option<&'static dyn AtomDynfo>];
|
||||
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() -> &'static [Option<&'static dyn AtomDynfo>] {
|
||||
&[/*Some(Fun::INFO)*/]
|
||||
fn general_atoms() -> impl Iterator<Item = Option<Box<dyn AtomDynfo>>> {
|
||||
[/*Some(Fun::INFO)*/].into_iter()
|
||||
}
|
||||
|
||||
pub fn atom_info_for(
|
||||
sys: &(impl DynSystemCard + ?Sized),
|
||||
tid: TypeId,
|
||||
) -> Option<(api::AtomId, &'static dyn AtomDynfo)> {
|
||||
(sys.atoms().iter().enumerate().map(|(i, o)| (NonZero::new(i as u64 + 1).unwrap(), o)))
|
||||
.chain(general_atoms().iter().enumerate().map(|(i, o)| (NonZero::new(!(i as u64)).unwrap(), o)))
|
||||
.filter_map(|(i, o)| o.as_ref().map(|a| (api::AtomId(i), *a)))
|
||||
) -> 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)
|
||||
}
|
||||
|
||||
pub fn atom_by_idx(
|
||||
sys: &(impl DynSystemCard + ?Sized),
|
||||
tid: api::AtomId,
|
||||
) -> Option<&'static dyn AtomDynfo> {
|
||||
) -> Option<Box<dyn AtomDynfo>> {
|
||||
if (u64::from(tid.0) >> (u64::BITS - 1)) & 1 == 1 {
|
||||
general_atoms()[!u64::from(tid.0) as usize]
|
||||
general_atoms().nth(!u64::from(tid.0) as usize).unwrap()
|
||||
} else {
|
||||
sys.atoms()[u64::from(tid.0) as usize - 1]
|
||||
sys.atoms().nth(u64::from(tid.0) as usize - 1).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resolv_atom(
|
||||
sys: &(impl DynSystemCard + ?Sized),
|
||||
atom: &api::Atom,
|
||||
) -> &'static dyn AtomDynfo {
|
||||
) -> 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) -> &'static [Option<&'static dyn AtomDynfo>] { Self::ATOM_DEFS }
|
||||
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>, GenMemberKind)>;
|
||||
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>, GenMemberKind>;
|
||||
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>, GenMemberKind> { Self::env().into_iter().collect() }
|
||||
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 }
|
||||
}
|
||||
|
||||
@@ -101,7 +108,7 @@ pub fn downcast_atom<A: AtomicFeatures>(foreign: ForeignAtom) -> Result<TypAtom<
|
||||
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, _)| AtomId::decode(&mut data) == *pos);
|
||||
.filter(|(pos, _)| api::AtomId::decode(&mut data) == *pos);
|
||||
match info_ent {
|
||||
None => Err(foreign),
|
||||
Some((_, info)) => {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use std::num::NonZero;
|
||||
use std::ops::Range;
|
||||
use std::sync::Arc;
|
||||
|
||||
use dyn_clone::{clone_box, DynClone};
|
||||
use hashbrown::HashMap;
|
||||
@@ -8,7 +7,9 @@ use itertools::Itertools;
|
||||
use orchid_base::interner::{intern, Tok};
|
||||
use orchid_base::location::Pos;
|
||||
use orchid_base::name::Sym;
|
||||
use orchid_base::parse::Comment;
|
||||
use orchid_base::tree::{TokTree, Token};
|
||||
use ordered_float::NotNan;
|
||||
use substack::Substack;
|
||||
use trait_set::trait_set;
|
||||
|
||||
@@ -16,8 +17,9 @@ use crate::api;
|
||||
use crate::atom::{AtomFactory, ForeignAtom};
|
||||
use crate::conv::ToExpr;
|
||||
use crate::entrypoint::MemberRecord;
|
||||
use crate::expr::GenExpr;
|
||||
use crate::expr::Expr;
|
||||
use crate::func_atom::{ExprFunc, Fun};
|
||||
use crate::macros::Rule;
|
||||
use crate::system::SysCtx;
|
||||
|
||||
pub type GenTokTree<'a> = TokTree<'a, ForeignAtom<'a>, AtomFactory>;
|
||||
@@ -27,68 +29,85 @@ 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)) }
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
pub struct GenItem {
|
||||
pub item: GenItemKind,
|
||||
pub comments: Vec<(String, 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.item {
|
||||
GenItemKind::Raw(item) => api::ItemKind::Raw(Vec::from_iter(
|
||||
item.into_iter().map(|t| t.to_api(&mut |f, r| do_extra(f, r, ctx.sys()))),
|
||||
)),
|
||||
let kind = match self.kind {
|
||||
GenItemKind::Export(n) => api::ItemKind::Export(n.marker()),
|
||||
GenItemKind::Member(mem) => api::ItemKind::Member(mem.into_api(ctx)),
|
||||
GenItemKind::Import(cn) => api::ItemKind::Import(cn.tok().marker()),
|
||||
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(|(s, p)| (Arc::new(s), p.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) -> GenItem {
|
||||
let kind = GenMemberKind::Const(value.to_expr());
|
||||
GenItemKind::Member(GenMember { exported: public, name: intern(name), kind }).at(Pos::Inherit)
|
||||
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)
|
||||
}
|
||||
pub fn module(
|
||||
public: bool,
|
||||
name: &str,
|
||||
imports: impl IntoIterator<Item = Sym>,
|
||||
items: impl IntoIterator<Item = GenItem>,
|
||||
) -> GenItem {
|
||||
items: impl IntoIterator<Item = Vec<GenItem>>,
|
||||
) -> Vec<GenItem> {
|
||||
let (name, kind) = root_mod(name, imports, items);
|
||||
GenItemKind::Member(GenMember { exported: public, name, kind }).at(Pos::Inherit)
|
||||
with_export(GenMember { name, kind }, public)
|
||||
}
|
||||
pub fn root_mod(
|
||||
name: &str,
|
||||
imports: impl IntoIterator<Item = Sym>,
|
||||
items: impl IntoIterator<Item = GenItem>,
|
||||
) -> (Tok<String>, GenMemberKind) {
|
||||
let kind = GenMemberKind::Mod {
|
||||
items: impl IntoIterator<Item = Vec<GenItem>>,
|
||||
) -> (Tok<String>, MemKind) {
|
||||
let kind = MemKind::Mod {
|
||||
imports: imports.into_iter().collect(),
|
||||
items: items.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>) -> GenItem {
|
||||
let fac = LazyMemberFactory::new(move |sym| GenMemberKind::Const(Fun::new(sym, xf).to_expr()));
|
||||
let mem = GenMember { exported, name: intern(name), kind: GenMemberKind::Lazy(fac) };
|
||||
GenItemKind::Member(mem).at(Pos::Inherit)
|
||||
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)
|
||||
}
|
||||
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()]
|
||||
}
|
||||
|
||||
pub fn comments<'a>(cmts: impl IntoIterator<Item = &'a str>, mut val: GenItem) -> GenItem {
|
||||
val.comments.extend(cmts.into_iter().map(|c| (c.to_string(), Pos::Inherit)));
|
||||
pub fn comments<'a>(
|
||||
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
|
||||
}
|
||||
|
||||
trait_set! {
|
||||
trait LazyMemberCallback = FnOnce(Sym) -> GenMemberKind + 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) -> GenMemberKind + Send + Sync + Clone + 'static) -> Self {
|
||||
pub fn new(cb: impl FnOnce(Sym) -> MemKind + Send + Sync + Clone + 'static) -> Self {
|
||||
Self(Box::new(cb))
|
||||
}
|
||||
pub fn build(self, path: Sym) -> GenMemberKind { (self.0)(path) }
|
||||
pub fn build(self, path: Sym) -> MemKind { (self.0)(path) }
|
||||
}
|
||||
impl Clone for LazyMemberFactory {
|
||||
fn clone(&self) -> Self { Self(clone_box(&*self.0)) }
|
||||
@@ -96,42 +115,48 @@ impl Clone for LazyMemberFactory {
|
||||
|
||||
pub enum GenItemKind {
|
||||
Member(GenMember),
|
||||
Raw(Vec<GenTokTree<'static>>),
|
||||
Export(Tok<String>),
|
||||
Import(Sym),
|
||||
Macro(Option<NotNan<f64>>, Vec<Rule>),
|
||||
}
|
||||
impl GenItemKind {
|
||||
pub fn at(self, position: Pos) -> GenItem {
|
||||
GenItem { item: self, comments: vec![], pos: position }
|
||||
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 {
|
||||
exported: bool,
|
||||
name: Tok<String>,
|
||||
kind: GenMemberKind,
|
||||
kind: MemKind,
|
||||
}
|
||||
impl GenMember {
|
||||
pub fn into_api(self, ctx: &mut impl TreeIntoApiCtx) -> api::Member {
|
||||
api::Member {
|
||||
name: self.name.marker(),
|
||||
exported: self.exported,
|
||||
kind: self.kind.into_api(&mut ctx.push_path(self.name)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum GenMemberKind {
|
||||
Const(GenExpr),
|
||||
pub enum MemKind {
|
||||
Const(Expr),
|
||||
Mod { imports: Vec<Sym>, items: Vec<GenItem> },
|
||||
Lazy(LazyMemberFactory),
|
||||
}
|
||||
impl GenMemberKind {
|
||||
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.into_api(ctx.sys())),
|
||||
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 {
|
||||
imports: imports.into_iter().map(|t| t.tok().marker()).collect(),
|
||||
items: items.into_iter().map(|i| i.into_api(ctx)).collect_vec(),
|
||||
items: (imports.into_iter())
|
||||
.map(|t| GenItemKind::Import(t).gen())
|
||||
.chain(items)
|
||||
.map(|i| i.into_api(ctx))
|
||||
.collect_vec(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user