New plans for macros

About to move them completely to stdlib
This commit is contained in:
2024-08-18 22:57:06 +02:00
parent 11951ede43
commit 3a63894de2
78 changed files with 2557 additions and 1980 deletions

View File

@@ -1,20 +1,25 @@
use std::any::{type_name, Any, TypeId};
use std::fmt;
use std::io::{Read, Write};
use std::ops::Deref;
use std::marker::PhantomData;
use std::ops::{Deref, Range};
use std::sync::OnceLock;
use dyn_clone::{clone_box, DynClone};
use never::Never;
use orchid_api::atom::{Atom, Fwd, LocalAtom};
use orchid_api::expr::ExprTicket;
use orchid_api_traits::{Coding, Decode, Request};
use orchid_api::ExprTicket;
use orchid_api_traits::{enc_vec, Coding, Decode, Request};
use orchid_base::error::{mk_err, OrcErr, OrcRes};
use orchid_base::intern;
use orchid_base::location::Pos;
use orchid_base::reqnot::Requester;
use orchid_base::tree::AtomInTok;
use trait_set::trait_set;
use crate::error::{ProjectError, ProjectResult};
use crate::api;
// use crate::error::{ProjectError, ProjectResult};
use crate::expr::{ExprHandle, GenClause, GenExpr, OwnedExpr};
use crate::system::{atom_info_for, downcast_atom, DynSystem, DynSystemCard, SysCtx};
use crate::system::{atom_info_for, downcast_atom, DynSystemCard, SysCtx};
pub trait AtomCard: 'static + Sized {
type Data: Clone + Coding + Sized;
@@ -37,6 +42,15 @@ pub trait AtomicFeatures: Atomic {
type Info: AtomDynfo;
const INFO: &'static Self::Info;
}
pub trait ToAtom {
fn to_atom_factory(self) -> AtomFactory;
}
impl<A: AtomicFeatures> ToAtom for A {
fn to_atom_factory(self) -> AtomFactory { self.factory() }
}
impl ToAtom for AtomFactory {
fn to_atom_factory(self) -> AtomFactory { self }
}
pub trait AtomicFeaturesImpl<Variant: AtomicVariant> {
fn _factory(self) -> AtomFactory;
type _Info: AtomDynfo;
@@ -48,37 +62,69 @@ impl<A: Atomic + AtomicFeaturesImpl<A::Variant> + ?Sized> AtomicFeatures for A {
const INFO: &'static Self::Info = Self::_INFO;
}
pub fn get_info<A: AtomCard>(sys: &(impl DynSystemCard + ?Sized)) -> (u64, &'static dyn AtomDynfo) {
pub fn get_info<A: AtomCard>(
sys: &(impl DynSystemCard + ?Sized)
) -> (api::AtomId, &'static dyn AtomDynfo) {
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 {
pub expr: ExprHandle,
pub atom: Atom,
pub struct ForeignAtom<'a> {
pub expr: Option<ExprHandle>,
pub char_marker: PhantomData<&'a ()>,
pub ctx: SysCtx,
pub atom: api::Atom,
pub pos: Pos,
}
impl ForeignAtom {
pub fn oex(self) -> OwnedExpr {
let gen_expr = GenExpr { pos: self.pos, clause: GenClause::Atom(self.expr.tk, self.atom) };
OwnedExpr { handle: self.expr, val: OnceLock::from(Box::new(gen_expr)) }
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)) }
})
}
}
impl ForeignAtom<'static> {
pub fn oex(self) -> OwnedExpr { self.oex_opt().unwrap() }
}
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> {
type Context = SysCtx;
fn from_api(atom: &api::Atom, pos: Range<u32>, ctx: &mut Self::Context) -> Self {
Self {
atom: atom.clone(),
char_marker: PhantomData,
ctx: ctx.clone(),
expr: None,
pos: Pos::Range(pos),
}
}
fn to_api(&self) -> orchid_api::Atom { self.atom.clone() }
}
pub struct NotTypAtom(pub Pos, pub OwnedExpr, pub &'static dyn AtomDynfo);
impl ProjectError for NotTypAtom {
const DESCRIPTION: &'static str = "Not the expected type";
fn message(&self) -> String { format!("This expression is not a {}", self.2.name()) }
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()],
)
}
}
#[derive(Clone)]
pub struct TypAtom<A: AtomicFeatures> {
pub data: ForeignAtom,
pub struct TypAtom<'a, A: AtomicFeatures> {
pub data: ForeignAtom<'a>,
pub value: A::Data,
}
impl<A: AtomicFeatures> TypAtom<A> {
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)),
@@ -88,71 +134,77 @@ impl<A: AtomicFeatures> TypAtom<A> {
},
}
}
}
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.expr.ctx.reqnot.request(Fwd(self.data.atom.clone(), req.enc_vec()))[..],
&mut &self.data.ctx.reqnot.request(api::Fwd(self.data.atom.clone(), enc_vec(&req)))[..],
)
}
}
impl<A: AtomicFeatures> Deref for TypAtom<A> {
impl<'a, A: AtomicFeatures> Deref for TypAtom<'a, A> {
type Target = A::Data;
fn deref(&self) -> &Self::Target { &self.value }
}
pub struct AtomCtx<'a>(pub &'a [u8], pub SysCtx);
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: ExprTicket) -> GenExpr;
fn call_ref(&self, ctx: AtomCtx<'_>, arg: ExprTicket) -> GenExpr;
fn same(&self, ctx: AtomCtx<'_>, buf2: &[u8]) -> bool;
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 print(&self, ctx: AtomCtx<'_>) -> String;
fn handle_req(&self, ctx: AtomCtx<'_>, req: &mut dyn Read, rep: &mut dyn Write);
fn command(&self, ctx: AtomCtx<'_>) -> ProjectResult<Option<GenExpr>>;
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 drop(&self, ctx: AtomCtx<'_>);
}
trait_set! {
pub trait AtomFactoryFn = FnOnce(&dyn DynSystem) -> LocalAtom + 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(&dyn DynSystem) -> LocalAtom + Clone + Send + Sync + 'static) -> Self {
pub fn new(f: impl FnOnce(SysCtx) -> api::Atom + Clone + Send + Sync + 'static) -> Self {
Self(Box::new(f))
}
pub fn build(self, sys: &dyn DynSystem) -> LocalAtom { (self.0)(sys) }
pub fn build(self, ctx: SysCtx) -> api::Atom { (self.0)(ctx) }
}
impl Clone for AtomFactory {
fn clone(&self) -> Self { AtomFactory(clone_box(&*self.0)) }
}
pub struct ErrNotCallable;
impl ProjectError for ErrNotCallable {
const DESCRIPTION: &'static str = "This atom is not callable";
pub fn err_not_callable() -> OrcErr {
mk_err(intern!(str: "This atom is not callable"), "Attempted to apply value as function", [])
}
pub struct ErrorNotCommand;
impl ProjectError for ErrorNotCommand {
const DESCRIPTION: &'static str = "This atom is not a command";
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)
fn unpack<'a>(self) -> (T::Req, &'a mut Self::W, SysCtx)
where Self: 'a;
fn never(self)
where T: AtomCard<Req = Never> {
}
}
pub struct RequestPack<'a, T: AtomCard + ?Sized, W: Write + ?Sized>(pub T::Req, pub &'a mut W);
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)
fn unpack<'b>(self) -> (<T as AtomCard>::Req, &'b mut Self::W, SysCtx)
where 'a: 'b {
(self.0, self.1)
(self.req, self.write, self.sys)
}
}

View File

@@ -2,18 +2,17 @@ use std::any::{type_name, Any, TypeId};
use std::borrow::Cow;
use std::io::{Read, Write};
use std::marker::PhantomData;
use std::num::NonZeroU64;
use std::sync::Arc;
use orchid_api::atom::LocalAtom;
use orchid_api::expr::ExprTicket;
use orchid_api_traits::{Decode, Encode};
use itertools::Itertools;
use orchid_api_traits::{enc_vec, Decode, Encode};
use orchid_base::error::OrcRes;
use orchid_base::id_store::{IdRecord, IdStore};
use crate::api;
use crate::atom::{
get_info, AtomCard, AtomCtx, AtomDynfo, AtomFactory, Atomic, AtomicFeaturesImpl, AtomicVariant, ErrNotCallable, ErrorNotCommand, ReqPck, RequestPack
err_not_callable, err_not_command, get_info, AtomCard, AtomCtx, AtomDynfo, AtomFactory, Atomic,
AtomicFeaturesImpl, AtomicVariant, ReqPck, RequestPack,
};
use crate::error::ProjectResult;
use crate::expr::{bot, ExprHandle, GenExpr};
use crate::system::SysCtx;
@@ -21,56 +20,114 @@ pub struct OwnedVariant;
impl AtomicVariant for OwnedVariant {}
impl<A: OwnedAtom + Atomic<Variant = OwnedVariant>> AtomicFeaturesImpl<OwnedVariant> for A {
fn _factory(self) -> AtomFactory {
AtomFactory::new(move |sys| {
AtomFactory::new(move |ctx| {
let rec = OBJ_STORE.add(Box::new(self));
let mut data = get_info::<A>(sys.dyn_card()).0.enc_vec();
rec.id().encode(&mut data);
let (id, _) = get_info::<A>(ctx.cted.inst().card());
let mut data = enc_vec(&id);
rec.encode(&mut data);
LocalAtom { drop: true, data }
api::Atom { drop: Some(api::AtomId(rec.id())), data, owner: ctx.id }
})
}
type _Info = OwnedAtomDynfo<A>;
const _INFO: &'static Self::_Info = &OwnedAtomDynfo(PhantomData);
}
fn with_atom<U>(mut b: &[u8], f: impl FnOnce(IdRecord<'_, Box<dyn DynOwnedAtom>>) -> U) -> U {
let id = NonZeroU64::decode(&mut b);
f(OBJ_STORE.get(id).unwrap_or_else(|| panic!("Received invalid atom ID: {id}")))
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>);
impl<T: OwnedAtom> AtomDynfo for OwnedAtomDynfo<T> {
fn print(&self, AtomCtx(buf, ctx): AtomCtx<'_>) -> String {
with_atom(buf, |a| a.dyn_print(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> {
fn decode(&self, AtomCtx(data, ..): AtomCtx) -> Box<dyn Any> {
Box::new(<T as AtomCard>::Data::decode(&mut &data[..]))
}
fn call(&self, AtomCtx(buf, ctx): AtomCtx, arg: ExprTicket) -> GenExpr {
with_atom(buf, |a| a.remove().dyn_call(ctx, arg))
fn call(&self, AtomCtx(_, id, ctx): AtomCtx, arg: api::ExprTicket) -> GenExpr {
with_atom(id.unwrap(), |a| a.remove().dyn_call(ctx, arg))
}
fn call_ref(&self, AtomCtx(buf, ctx): AtomCtx, arg: ExprTicket) -> GenExpr {
with_atom(buf, |a| a.dyn_call_ref(ctx, arg))
fn call_ref(&self, AtomCtx(_, id, ctx): AtomCtx, arg: api::ExprTicket) -> GenExpr {
with_atom(id.unwrap(), |a| a.dyn_call_ref(ctx, arg))
}
fn same(&self, AtomCtx(buf, ctx): AtomCtx, buf2: &[u8]) -> bool {
with_atom(buf, |a1| with_atom(buf2, |a2| a1.dyn_same(ctx, &**a2)))
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(buf, ctx): AtomCtx, req: &mut dyn Read, rep: &mut dyn Write) {
with_atom(buf, |a| a.dyn_handle_req(ctx, 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(buf, ctx): AtomCtx<'_>) -> ProjectResult<Option<GenExpr>> {
with_atom(buf, |a| a.remove().dyn_command(ctx))
fn command(&self, AtomCtx(_, id, ctx): AtomCtx<'_>) -> OrcRes<Option<GenExpr>> {
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) -> 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()
}
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 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;
}
struct DeserCtxImpl<'a>(&'a [u8], &'a SysCtx);
impl<'a> DeserializeCtx for DeserCtxImpl<'a> {
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 = ExprHandle> + ExactSizeIterator>(refs: I) -> Self;
fn to_vec(self) -> Vec<ExprHandle>;
}
impl RefSet for () {
fn to_vec(self) -> Vec<ExprHandle> { Vec::new() }
fn from_iter<I: Iterator<Item = ExprHandle> + 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<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 {
assert_eq!(refs.len(), N, "Wrong number of refs provided");
refs.collect_vec().try_into().unwrap_or_else(|_: Vec<_>| unreachable!())
}
fn drop(&self, AtomCtx(buf, ctx): AtomCtx) { with_atom(buf, |a| a.remove().dyn_free(ctx)) }
}
/// Atoms that have a [Drop]
pub trait OwnedAtom: Atomic<Variant = OwnedVariant> + Send + Sync + Any + Clone + 'static {
type Refs: RefSet;
fn val(&self) -> Cow<'_, Self::Data>;
#[allow(unused_variables)]
fn call_ref(&self, arg: ExprHandle) -> GenExpr { bot(ErrNotCallable) }
fn call_ref(&self, arg: ExprHandle) -> GenExpr { bot(err_not_callable()) }
fn call(self, arg: ExprHandle) -> GenExpr {
let ctx = arg.get_ctx();
let gcl = self.call_ref(arg);
@@ -79,40 +136,42 @@ pub trait OwnedAtom: Atomic<Variant = OwnedVariant> + Send + Sync + Any + Clone
}
#[allow(unused_variables)]
fn same(&self, ctx: SysCtx, other: &Self) -> bool {
eprintln!(
"Override OwnedAtom::same for {} if it can be generated during parsing",
type_name::<Self>()
);
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, ctx: SysCtx, pck: impl ReqPck<Self>);
fn handle_req(&self, pck: impl ReqPck<Self>);
#[allow(unused_variables)]
fn command(self, ctx: SysCtx) -> ProjectResult<Option<GenExpr>> { Err(Arc::new(ErrorNotCommand)) }
fn command(self, ctx: SysCtx) -> OrcRes<Option<GenExpr>> { Err(vec![err_not_command()]) }
#[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;
fn deserialize(ctx: impl DeserializeCtx, refs: Self::Refs) -> 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: ExprTicket) -> GenExpr;
fn dyn_call(self: Box<Self>, ctx: SysCtx, arg: ExprTicket) -> GenExpr;
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) -> ProjectResult<Option<GenExpr>>;
fn dyn_command(self: Box<Self>, ctx: SysCtx) -> OrcRes<Option<GenExpr>>;
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>;
}
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: ExprTicket) -> GenExpr {
fn dyn_call_ref(&self, ctx: SysCtx, arg: api::ExprTicket) -> GenExpr {
self.call_ref(ExprHandle::from_args(ctx, arg))
}
fn dyn_call(self: Box<Self>, ctx: SysCtx, arg: ExprTicket) -> GenExpr {
fn dyn_call(self: Box<Self>, ctx: SysCtx, arg: api::ExprTicket) -> GenExpr {
self.call(ExprHandle::from_args(ctx, arg))
}
fn dyn_same(&self, ctx: SysCtx, other: &dyn DynOwnedAtom) -> bool {
@@ -122,14 +181,16 @@ impl<T: OwnedAtom> DynOwnedAtom for T {
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, ctx: SysCtx, req: &mut dyn Read, rep: &mut dyn Write) {
self.handle_req(ctx, RequestPack::<T, dyn Write>(<Self as AtomCard>::Req::decode(req), rep))
}
fn dyn_command(self: Box<Self>, ctx: SysCtx) -> ProjectResult<Option<GenExpr>> {
self.command(ctx)
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_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> {
self.serialize(ctx, sink).to_vec()
}
}
pub(crate) static OBJ_STORE: IdStore<Box<dyn DynOwnedAtom>> = IdStore::new();

View File

@@ -1,17 +1,16 @@
use std::any::{type_name, Any, TypeId};
use std::io::Write;
use std::marker::PhantomData;
use std::sync::Arc;
use orchid_api::atom::LocalAtom;
use orchid_api::expr::ExprTicket;
use orchid_api_traits::{Coding, Decode, Encode};
use orchid_api::ExprTicket;
use orchid_api_traits::{enc_vec, Coding, Decode};
use orchid_base::error::OrcRes;
use crate::api;
use crate::atom::{
get_info, AtomCard, AtomCtx, AtomDynfo, AtomFactory, Atomic, AtomicFeaturesImpl, AtomicVariant,
ErrNotCallable, ReqPck, RequestPack,
err_not_callable, err_not_command, get_info, AtomCard, AtomCtx, AtomDynfo, AtomFactory, Atomic,
AtomicFeaturesImpl, AtomicVariant, ReqPck, RequestPack,
};
use crate::error::ProjectResult;
use crate::expr::{bot, ExprHandle, GenExpr};
use crate::system::SysCtx;
@@ -19,10 +18,11 @@ pub struct ThinVariant;
impl AtomicVariant for ThinVariant {}
impl<A: ThinAtom + Atomic<Variant = ThinVariant>> AtomicFeaturesImpl<ThinVariant> for A {
fn _factory(self) -> AtomFactory {
AtomFactory::new(move |sys| {
let mut buf = get_info::<A>(sys.dyn_card()).0.enc_vec();
AtomFactory::new(move |ctx| {
let (id, _) = get_info::<A>(ctx.cted.inst().card());
let mut buf = enc_vec(&id);
self.encode(&mut buf);
LocalAtom { drop: false, data: buf }
api::Atom { drop: None, data: buf, owner: ctx.id }
})
}
type _Info = ThinAtomDynfo<Self>;
@@ -31,48 +31,59 @@ impl<A: ThinAtom + Atomic<Variant = ThinVariant>> AtomicFeaturesImpl<ThinVariant
pub struct ThinAtomDynfo<T: ThinAtom>(PhantomData<T>);
impl<T: ThinAtom> AtomDynfo for ThinAtomDynfo<T> {
fn print(&self, AtomCtx(buf, ctx): AtomCtx<'_>) -> String { T::decode(&mut &buf[..]).print(ctx) }
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: ExprTicket) -> GenExpr {
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 {
T::decode(&mut &buf[..]).call(ExprHandle::from_args(ctx, arg))
}
fn call_ref(&self, AtomCtx(buf, ctx): AtomCtx, arg: ExprTicket) -> GenExpr {
fn call_ref(&self, AtomCtx(buf, _, ctx): AtomCtx, arg: api::ExprTicket) -> GenExpr {
T::decode(&mut &buf[..]).call(ExprHandle::from_args(ctx, arg))
}
fn handle_req(
&self,
AtomCtx(buf, ctx): AtomCtx,
AtomCtx(buf, _, sys): AtomCtx,
req: &mut dyn std::io::Read,
rep: &mut dyn Write,
write: &mut dyn Write,
) {
T::decode(&mut &buf[..]).handle_req(ctx, RequestPack::<T, dyn Write>(Decode::decode(req), rep))
let pack = RequestPack::<T, dyn Write>{ req: Decode::decode(req), write, sys };
T::decode(&mut &buf[..]).handle_req(pack)
}
fn same(&self, AtomCtx(buf, ctx): AtomCtx, buf2: &[u8]) -> bool {
T::decode(&mut &buf[..]).same(ctx, &T::decode(&mut &buf2[..]))
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<'_>) -> ProjectResult<Option<GenExpr>> {
fn command(&self, AtomCtx(buf, _, ctx): AtomCtx<'_>) -> OrcRes<Option<GenExpr>> {
T::decode(&mut &buf[..]).command(ctx)
}
fn drop(&self, AtomCtx(buf, ctx): AtomCtx) {
let string_self = T::decode(&mut &buf[..]).print(ctx);
eprintln!("Received drop signal for non-drop atom {string_self:?}")
fn serialize(&self, AtomCtx(buf, _, _): AtomCtx<'_>, write: &mut dyn Write) -> Vec<ExprTicket> {
T::decode(&mut &buf[..]).encode(write);
Vec::new()
}
fn deserialize(&self, ctx: SysCtx, data: &[u8], refs: &[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> + Coding + Send + Sync + 'static {
pub trait ThinAtom: AtomCard<Data = Self> + Atomic<Variant = ThinVariant> + Coding + Send + Sync + 'static {
#[allow(unused_variables)]
fn call(&self, arg: ExprHandle) -> GenExpr { bot(ErrNotCallable) }
fn call(&self, arg: ExprHandle) -> GenExpr { bot(err_not_callable()) }
#[allow(unused_variables)]
fn same(&self, ctx: SysCtx, other: &Self) -> bool {
let tname = type_name::<Self>();
eprintln!("Override ThinAtom::same for {tname} if it can be generated during parsing");
writeln!(ctx.logger, "Override ThinAtom::same for {tname} if it can appear in macro input");
false
}
fn handle_req(&self, ctx: SysCtx, pck: impl ReqPck<Self>);
fn handle_req(&self, pck: impl ReqPck<Self>);
#[allow(unused_variables)]
fn command(&self, ctx: SysCtx) -> ProjectResult<Option<GenExpr>> { Err(Arc::new(ErrNotCallable)) }
fn command(&self, ctx: SysCtx) -> OrcRes<Option<GenExpr>> { Err(vec![err_not_command()]) }
#[allow(unused_variables)]
fn print(&self, ctx: SysCtx) -> String { format!("ThinAtom({})", type_name::<Self>()) }
}

View File

@@ -1,42 +1,39 @@
use orchid_base::error::{mk_err, OrcErr, OrcRes};
use orchid_base::intern;
use orchid_base::location::Pos;
use crate::atom::{AtomicFeatures, TypAtom};
use crate::error::{ProjectError, ProjectResult};
use crate::expr::{atom, bot_obj, ExprHandle, GenExpr, OwnedExpr};
use crate::atom::{AtomicFeatures, ToAtom, TypAtom};
use crate::expr::{atom, botv, ExprHandle, GenExpr, OwnedExpr};
use crate::system::downcast_atom;
pub trait TryFromExpr: Sized {
fn try_from_expr(expr: ExprHandle) -> ProjectResult<Self>;
fn try_from_expr(expr: ExprHandle) -> OrcRes<Self>;
}
impl TryFromExpr for OwnedExpr {
fn try_from_expr(expr: ExprHandle) -> ProjectResult<Self> { Ok(OwnedExpr::new(expr)) }
fn try_from_expr(expr: ExprHandle) -> OrcRes<Self> { Ok(OwnedExpr::new(expr)) }
}
impl<T: TryFromExpr, U: TryFromExpr> TryFromExpr for (T, U) {
fn try_from_expr(expr: ExprHandle) -> ProjectResult<Self> {
fn try_from_expr(expr: ExprHandle) -> OrcRes<Self> {
Ok((T::try_from_expr(expr.clone())?, U::try_from_expr(expr)?))
}
}
pub struct ErrorNotAtom(Pos);
impl ProjectError for ErrorNotAtom {
const DESCRIPTION: &'static str = "Expected an atom";
fn one_position(&self) -> Pos { self.0.clone() }
fn err_not_atom(pos: Pos) -> OrcErr {
mk_err(intern!(str: "Expected an atom"), "This expression is not an atom", [pos.into()])
}
pub struct ErrorUnexpectedType(Pos);
impl ProjectError for ErrorUnexpectedType {
const DESCRIPTION: &'static str = "Type error";
fn one_position(&self) -> Pos { self.0.clone() }
fn err_type(pos: Pos) -> OrcErr {
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: ExprHandle) -> ProjectResult<Self> {
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| ErrorNotAtom(ex.pos.clone()).pack())
.and_then(|f| downcast_atom(f).map_err(|f| ErrorUnexpectedType(f.pos).pack()))
.map_err(|ex| vec![err_not_atom(ex.pos.clone())])
.and_then(|f| downcast_atom(f).map_err(|f| vec![err_type(f.pos)]))
}
}
@@ -44,15 +41,19 @@ pub trait ToExpr {
fn to_expr(self) -> GenExpr;
}
impl<T: ToExpr> ToExpr for ProjectResult<T> {
impl ToExpr for GenExpr {
fn to_expr(self) -> GenExpr { self }
}
impl<T: ToExpr> ToExpr for OrcRes<T> {
fn to_expr(self) -> GenExpr {
match self {
Err(e) => bot_obj(e),
Err(e) => botv(e),
Ok(t) => t.to_expr(),
}
}
}
impl<A: AtomicFeatures> ToExpr for A {
impl<A: ToAtom> ToExpr for A {
fn to_expr(self) -> GenExpr { atom(self) }
}

View File

@@ -6,120 +6,133 @@ use std::{mem, process, thread};
use hashbrown::HashMap;
use itertools::Itertools;
use orchid_api::atom::{
Atom, AtomDrop, AtomPrint, AtomReq, AtomSame, CallRef, Command, FinalCall, Fwded, NextStep
};
use orchid_api::interner::Sweep;
use orchid_api::parser::{CharFilter, LexExpr, LexedExpr, ParserReq};
use orchid_api::proto::{ExtMsgSet, ExtensionHeader, HostExtNotif, HostExtReq, HostHeader, Ping};
use orchid_api::system::{SysDeclId, SysId, SystemDrop, SystemInst};
use orchid_api::tree::{GetMember, TreeId};
use orchid_api::vfs::{EagerVfs, GetVfs, VfsId, VfsRead, VfsReq};
use orchid_api_traits::{Decode, Encode};
use orchid_api::DeserAtom;
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::name::PathSlice;
use orchid_base::name::{PathSlice, Sym};
use orchid_base::parse::Snippet;
use orchid_base::reqnot::{ReqNot, Requester};
use orchid_base::tree::{ttv_from_api, ttv_to_api};
use substack::Substack;
use crate::api;
use crate::atom::{AtomCtx, AtomDynfo};
use crate::error::errv_to_apiv;
use crate::atom_owned::OBJ_STORE;
use crate::fs::VirtFS;
use crate::lexer::{CascadingError, LexContext, NotApplicableLexerError};
use crate::lexer::{err_cascade, err_lexer_na, LexContext};
use crate::msg::{recv_parent_msg, send_parent_msg};
use crate::system::{atom_by_idx, resolv_atom, SysCtx};
use crate::system::{atom_by_idx, SysCtx};
use crate::system_ctor::{CtedObj, DynSystemCtor};
use crate::tree::{LazyMemberFactory, TIACtxImpl};
use crate::tree::{do_extra, GenTok, GenTokTree, LazyMemberFactory, TIACtxImpl};
pub struct ExtensionData {
pub thread_name: &'static str,
pub name: &'static str,
pub systems: &'static [&'static dyn DynSystemCtor],
}
impl ExtensionData {
pub fn new(thread_name: &'static str, systems: &'static [&'static dyn DynSystemCtor]) -> Self {
Self { thread_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(LazyMemberFactory),
Gen(Sym, LazyMemberFactory),
Res,
}
pub struct SystemRecord {
cted: CtedObj,
vfses: HashMap<VfsId, &'static dyn VirtFS>,
declfs: EagerVfs,
lazy_members: HashMap<TreeId, MemberRecord>,
vfses: HashMap<api::VfsId, &'static dyn VirtFS>,
declfs: api::EagerVfs,
lazy_members: HashMap<api::TreeId, MemberRecord>,
}
pub fn with_atom_record<T>(
systems: &Mutex<HashMap<SysId, SystemRecord>>,
atom: &Atom,
cb: impl FnOnce(&'static dyn AtomDynfo, CtedObj, &[u8]) -> 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,
) -> T {
let mut data = &atom.data[..];
let systems_g = systems.lock().unwrap();
let cted = &systems_g[&atom.owner].cted;
let sys = cted.inst();
let atom_record = atom_by_idx(sys.dyn_card(), u64::decode(&mut data)).expect("Atom ID reserved");
cb(atom_record, cted.clone(), 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(data.thread_name.to_string()).spawn(|| extension_main_logic(data)).unwrap().join().is_err() {
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 HostHeader{ log_strategy } = HostHeader::decode(&mut std::io::stdin().lock());
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(SysDeclId(NonZero::new(id + 1).unwrap())))
.map(|(id, sys)| sys.decl(api::SysDeclId(NonZero::new(id + 1).unwrap())))
.collect_vec();
let systems = Arc::new(Mutex::new(HashMap::<SysId, SystemRecord>::new()));
ExtensionHeader { systems: decls.clone() }.encode(&mut buf);
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 rn = ReqNot::<ExtMsgSet>::new(
|a, _| {
eprintln!("Upsending {:?}", a);
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, logger; move |n, reqnot| match n {
HostExtNotif::Exit => exiting.store(true, Ordering::Relaxed),
HostExtNotif::SystemDrop(SystemDrop(sys_id)) =>
}),
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)),
HostExtNotif::AtomDrop(AtomDrop(atom)) => {
with_atom_record(&systems, &atom, |rec, cted, data| {
rec.drop(AtomCtx(data, SysCtx{ reqnot, logger: logger.clone(), id: atom.owner, cted }))
})
}
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() {
HostExtReq::Ping(ping@Ping) => req.handle(ping, &()),
HostExtReq::Sweep(sweep@Sweep) => req.handle(sweep, &sweep_replica()),
HostExtReq::NewSystem(new_sys) => {
api::HostExtReq::Ping(ping@api::Ping) => req.handle(ping, &()),
api::HostExtReq::Sweep(sweep@api::Sweep) => req.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(CharFilter(vec![]), |cf, lx| {
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: req.reqnot()
};
let mut tia_ctx = TIACtxImpl{
lazy: &mut lazy_mems,
ctx: ctx.clone(),
basepath: &[],
path: Substack::Bottom,
};
let const_root = (cted.inst().dyn_env().into_iter())
.map(|(k, v)| {
(k.marker(), v.into_api(&mut TIACtxImpl{ lazy: &mut lazy_mems, sys: &*cted.inst()}))
})
.map(|(k, v)| (k.marker(), 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),
@@ -127,106 +140,128 @@ fn extension_main_logic(data: ExtensionData) {
cted,
lazy_members: lazy_mems
});
req.handle(new_sys, &SystemInst {
req.handle(new_sys, &api::SystemInst {
lex_filter,
const_root,
parses_lines: vec!()
line_types: vec![]
})
}
HostExtReq::GetMember(get_tree@GetMember(sys_id, tree_id)) => {
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 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(cb)) => cb,
Some(MemberRecord::Gen(path, cb)) => (path, cb),
};
let tree = cb.build();
let reply_tree = tree.into_api(&mut TIACtxImpl{ sys: &*sys.cted.inst(), lazy });
req.handle(get_tree, &reply_tree);
let tree = cb.build(path.clone());
let ctx = SysCtx::new(*sys_id, &sys.cted, &logger, req.reqnot());
let reply_tree = tree.into_api(&mut TIACtxImpl{ ctx: ctx.clone(), lazy, path: Substack::Bottom, basepath: &path });
req.handle(get_tree, &reply_tree)
}
HostExtReq::VfsReq(VfsReq::GetVfs(get_vfs@GetVfs(sys_id))) => {
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)
}
HostExtReq::VfsReq(VfsReq::VfsRead(vfs_read@VfsRead(sys_id, vfs_id, path))) => {
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| deintern(*t)).collect_vec();
req.handle(vfs_read, &systems_g[sys_id].vfses[vfs_id].load(PathSlice::new(&path)))
}
HostExtReq::ParserReq(ParserReq::LexExpr(lex)) => {
let LexExpr{ sys, text, pos, id } = *lex;
api::HostExtReq::ParserReq(api::ParserReq::LexExpr(lex)) => {
let api::LexExpr{ sys, text, pos, id } = *lex;
let systems_g = systems.lock().unwrap();
let lexers = systems_g[&sys].cted.inst().dyn_lexers();
mem::drop(systems_g);
let text = deintern(text);
let tk = req.will_handle_as(lex);
thread::spawn(clone!(systems; move || {
let ctx = LexContext { sys, id, pos, reqnot: req.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.as_any_ref().is::<NotApplicableLexerError>() => continue,
Err(e) if e.as_any_ref().is::<CascadingError>() => return req.handle_as(tk, &None),
Err(e) => return req.handle_as(tk, &Some(Err(errv_to_apiv([e])))),
Ok((s, expr)) => {
let systems_g = systems.lock().unwrap();
let expr = expr.into_api(&*systems_g[&sys].cted.inst());
let pos = (text.len() - s.len()) as u32;
return req.handle_as(tk, &Some(Ok(LexedExpr{ pos, expr })))
}
let ctx = LexContext { sys, id, pos, reqnot: req.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) => {
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))})
},
Ok((s, expr)) => {
let ctx = mk_ctx(sys, req.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 })))
}
}
eprintln!("Got notified about n/a character '{trigger_char}'");
req.handle_as(tk, &None)
}));
},
HostExtReq::AtomReq(atom_req) => {
let systems_g = systems.lock().unwrap();
let atom = atom_req.get_atom();
let sys = &systems_g[&atom.owner];
let ctx = SysCtx {
cted: sys.cted.clone(),
id: atom.owner,
logger: logger.clone(),
reqnot: req.reqnot()
};
let dynfo = resolv_atom(&*sys.cted.inst(), atom);
let actx = AtomCtx(&atom.data[8..], ctx);
match atom_req {
AtomReq::AtomPrint(print@AtomPrint(_)) => req.handle(print, &dynfo.print(actx)),
AtomReq::AtomSame(same@AtomSame(_, r)) => {
// different systems or different type tags
if atom.owner != r.owner || atom.data[..8] != r.data[..8] {
return req.handle(same, &false)
}
req.handle(same, &dynfo.same(actx, &r.data[8..]))
},
AtomReq::Fwded(fwded@Fwded(_, payload)) => {
let mut reply = Vec::new();
dynfo.handle_req(actx, &mut &payload[..], &mut reply);
req.handle(fwded, &reply)
}
AtomReq::CallRef(call@CallRef(_, arg))
=> req.handle(call, &dynfo.call_ref(actx, *arg).to_api(&*sys.cted.inst())),
AtomReq::FinalCall(call@FinalCall(_, arg))
=> req.handle(call, &dynfo.call(actx, *arg).to_api(&*sys.cted.inst())),
AtomReq::Command(cmd@Command(_)) => req.handle(cmd, &match dynfo.command(actx) {
Err(e) => Err(errv_to_apiv([e])),
Ok(opt) => Ok(match opt {
Some(cont) => NextStep::Continue(cont.into_api(&*sys.cted.inst())),
None => NextStep::Halt,
})
})
}
writeln!(logger, "Got notified about n/a character '{trigger_char}'");
req.handle(lex, &None)
},
api::HostExtReq::ParserReq(api::ParserReq::ParseLine(pline@api::ParseLine{ sys, line })) => {
let mut ctx = mk_ctx(*sys, req.reqnot());
let parsers = ctx.cted.inst().dyn_parsers();
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())),
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)
}
api::HostExtReq::AtomReq(atom_req) => {
let atom = atom_req.get_atom();
with_atom_record(&mk_ctx, req.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 = nfo.serialize(actx, &mut buf);
req.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)) => {
let mut reply = Vec::new();
nfo.handle_req(actx, &mut &payload[..], &mut reply);
req.handle(fwded, &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::HostExtReq::DeserAtom(deser@DeserAtom(sys, buf, refs)) => {
let mut read = &mut &buf[..];
let ctx = mk_ctx(*sys, req.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))
}
}),
);
init_replica(rn.clone().map());
while !exiting.load(Ordering::Relaxed) {
let rcvd = recv_parent_msg().unwrap();
// eprintln!("Downsent {rcvd:?}");
rn.receive(rcvd)
}
}

View File

@@ -6,15 +6,15 @@ use std::{fmt, iter};
use dyn_clone::{clone_box, DynClone};
use itertools::Itertools;
use orchid_api::error::{GetErrorDetails, ProjErr, ProjErrId};
use orchid_api::proto::ExtMsgSet;
use orchid_base::boxed_iter::{box_once, BoxedIter};
use orchid_base::clone;
use orchid_base::error::{ErrorPosition, OwnedError};
use orchid_base::error::{ErrPos, OrcError};
use orchid_base::interner::{deintern, intern};
use orchid_base::location::{GetSrc, Pos};
use orchid_base::reqnot::{ReqNot, Requester};
use crate::api;
/// Errors addressed to the developer which are to be resolved with
/// code changes
pub trait ProjectError: Sized + Send + Sync + 'static {
@@ -26,8 +26,8 @@ pub trait ProjectError: Sized + Send + Sync + 'static {
/// Code positions relevant to this error. If you don't implement this, you
/// must implement [ProjectError::one_position]
#[must_use]
fn positions(&self) -> impl IntoIterator<Item = ErrorPosition> + '_ {
box_once(ErrorPosition { position: self.one_position(), message: None })
fn positions(&self) -> impl IntoIterator<Item = ErrPos> + '_ {
box_once(ErrPos { position: self.one_position(), message: None })
}
/// Short way to provide a single origin. If you don't implement this, you
/// must implement [ProjectError::positions]
@@ -58,7 +58,7 @@ pub trait DynProjectError: Send + Sync + 'static {
fn message(&self) -> String { self.description().to_string() }
/// Code positions relevant to this error.
#[must_use]
fn positions(&self) -> BoxedIter<'_, ErrorPosition>;
fn positions(&self) -> BoxedIter<'_, ErrPos>;
}
impl<T> DynProjectError for T
@@ -68,9 +68,7 @@ where T: ProjectError
fn into_packed(self: Arc<Self>) -> ProjectErrorObj { self }
fn description(&self) -> Cow<'_, str> { Cow::Borrowed(T::DESCRIPTION) }
fn message(&self) -> String { ProjectError::message(self) }
fn positions(&self) -> BoxedIter<ErrorPosition> {
Box::new(ProjectError::positions(self).into_iter())
}
fn positions(&self) -> BoxedIter<ErrPos> { Box::new(ProjectError::positions(self).into_iter()) }
}
pub fn pretty_print(err: &dyn DynProjectError, get_src: &mut impl GetSrc) -> String {
@@ -82,7 +80,7 @@ pub fn pretty_print(err: &dyn DynProjectError, get_src: &mut impl GetSrc) -> Str
head + "No origins specified"
} else {
iter::once(head)
.chain(positions.iter().map(|ErrorPosition { position: origin, message }| match message {
.chain(positions.iter().map(|ErrPos { position: origin, message }| match message {
None => format!("@{}", origin.pretty_print(get_src)),
Some(msg) => format!("@{}: {msg}", origin.pretty_print(get_src)),
}))
@@ -95,7 +93,7 @@ impl DynProjectError for ProjectErrorObj {
fn description(&self) -> Cow<'_, str> { (**self).description() }
fn into_packed(self: Arc<Self>) -> ProjectErrorObj { (*self).clone() }
fn message(&self) -> String { (**self).message() }
fn positions(&self) -> BoxedIter<'_, ErrorPosition> { (**self).positions() }
fn positions(&self) -> BoxedIter<'_, ErrPos> { (**self).positions() }
}
/// Type-erased [ProjectError] implementor through the [DynProjectError]
@@ -179,8 +177,8 @@ impl<T: ErrorSansOrigin> DynProjectError for OriginBundle<T> {
fn into_packed(self: Arc<Self>) -> ProjectErrorObj { self }
fn description(&self) -> Cow<'_, str> { self.1.description() }
fn message(&self) -> String { self.1.message() }
fn positions(&self) -> BoxedIter<ErrorPosition> {
box_once(ErrorPosition { position: self.0.clone(), message: None })
fn positions(&self) -> BoxedIter<ErrPos> {
box_once(ErrPos { position: self.0.clone(), message: None })
}
}
@@ -259,7 +257,7 @@ struct MultiError(Vec<ProjectErrorObj>);
impl ProjectError for MultiError {
const DESCRIPTION: &'static str = "Multiple errors occurred";
fn message(&self) -> String { format!("{} errors occurred", self.0.len()) }
fn positions(&self) -> impl IntoIterator<Item = ErrorPosition> + '_ {
fn positions(&self) -> impl IntoIterator<Item = ErrPos> + '_ {
self.0.iter().flat_map(|e| {
e.positions().map(|pos| {
let emsg = e.message();
@@ -268,49 +266,35 @@ impl ProjectError for MultiError {
Some(s) if s.is_empty() => emsg,
Some(pmsg) => format!("{emsg}: {pmsg}"),
};
ErrorPosition { position: pos.position, message: Some(Arc::new(msg)) }
ErrPos { position: pos.position, message: Some(Arc::new(msg)) }
})
})
}
}
fn err_to_api(err: ProjectErrorObj) -> ProjErr {
ProjErr {
fn err_to_api(err: ProjectErrorObj) -> api::OrcErr {
api::OrcErr {
description: intern(&*err.description()).marker(),
message: Arc::new(err.message()),
locations: err.positions().map(|e| e.to_api()).collect_vec(),
}
}
pub fn errv_to_apiv(errv: impl IntoIterator<Item = ProjectErrorObj>) -> Vec<ProjErr> {
errv.into_iter().flat_map(unpack_err).map(err_to_api).collect_vec()
}
pub fn err_from_apiv<'a>(
err: impl IntoIterator<Item = &'a ProjErr>,
reqnot: &ReqNot<ExtMsgSet>
) -> ProjectErrorObj {
pack_err(err.into_iter().map(|e| {
let details: OnceLock<_> = OwnedError::from_api(e).into();
Arc::new(RelayedError { id: None, reqnot: reqnot.clone(), details }).into_packed()
}))
}
struct RelayedError {
pub id: Option<ProjErrId>,
pub reqnot: ReqNot<ExtMsgSet>,
pub details: OnceLock<OwnedError>,
pub id: Option<api::ErrId>,
pub reqnot: ReqNot<api::ExtMsgSet>,
pub details: OnceLock<OrcError>,
}
impl RelayedError {
fn details(&self) -> &OwnedError {
fn details(&self) -> &OrcError {
let Self { id, reqnot, details: data } = self;
data.get_or_init(clone!(reqnot; move || {
let id = id.expect("Either data or ID must be initialized");
let projerr = reqnot.request(GetErrorDetails(id));
OwnedError {
let projerr = reqnot.request(api::GetErrorDetails(id));
OrcError {
description: deintern(projerr.description),
message: projerr.message,
positions: projerr.locations.iter().map(ErrorPosition::from_api).collect_vec(),
positions: projerr.locations.iter().map(ErrPos::from_api).collect_vec(),
}
}))
}
@@ -320,7 +304,7 @@ impl DynProjectError for RelayedError {
fn message(&self) -> String { self.details().message.to_string() }
fn as_any_ref(&self) -> &dyn std::any::Any { self }
fn into_packed(self: Arc<Self>) -> ProjectErrorObj { self }
fn positions(&self) -> BoxedIter<'_, ErrorPosition> {
fn positions(&self) -> BoxedIter<'_, ErrPos> {
Box::new(self.details().positions.iter().cloned())
}
}

View File

@@ -1,25 +1,25 @@
use std::marker::PhantomData;
use std::ops::Deref;
use std::sync::{Arc, OnceLock};
use std::sync::OnceLock;
use derive_destructure::destructure;
use orchid_api::atom::Atom;
use orchid_api::expr::{Acquire, Clause, Expr, ExprTicket, Inspect, Release};
use orchid_base::error::{errv_from_apiv, errv_to_apiv, OrcErr};
use orchid_base::interner::{deintern, Tok};
use orchid_base::location::Pos;
use orchid_base::reqnot::Requester;
use crate::atom::{AtomFactory, AtomicFeatures, ForeignAtom};
use crate::error::{err_from_apiv, errv_to_apiv, DynProjectError, ProjectErrorObj};
use crate::system::{DynSystem, SysCtx};
use crate::api;
use crate::atom::{AtomFactory, ForeignAtom, ToAtom};
use crate::system::SysCtx;
#[derive(destructure)]
pub struct ExprHandle {
pub tk: ExprTicket,
pub tk: api::ExprTicket,
pub ctx: SysCtx,
}
impl ExprHandle {
pub(crate) fn from_args(ctx: SysCtx, tk: ExprTicket) -> Self { Self { ctx, tk } }
pub(crate) fn into_tk(self) -> ExprTicket {
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
}
@@ -27,12 +27,12 @@ impl ExprHandle {
}
impl Clone for ExprHandle {
fn clone(&self) -> Self {
self.ctx.reqnot.notify(Acquire(self.ctx.id, self.tk));
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(Release(self.ctx.id, self.tk)) }
fn drop(&mut self) { self.ctx.reqnot.notify(api::Release(self.ctx.id, self.tk)) }
}
#[derive(Clone, destructure)]
@@ -45,15 +45,21 @@ impl OwnedExpr {
pub fn get_data(&self) -> &GenExpr {
self.val.get_or_init(|| {
Box::new(GenExpr::from_api(
self.handle.ctx.reqnot.request(Inspect(self.handle.tk)).expr,
self.handle.ctx.reqnot.request(api::Inspect(self.handle.tk)).expr,
&self.handle.ctx,
))
})
}
pub fn foreign_atom(self) -> Result<ForeignAtom, Self> {
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 { expr: self.handle, atom, pos: position });
return Ok(ForeignAtom {
ctx: self.handle.ctx.clone(),
expr: Some(self.handle),
char_marker: PhantomData,
pos: position,
atom,
});
}
Err(self)
}
@@ -69,13 +75,13 @@ pub struct GenExpr {
pub clause: GenClause,
}
impl GenExpr {
pub fn to_api(&self, sys: &dyn DynSystem) -> Expr {
Expr { location: self.pos.to_api(), clause: self.clause.to_api(sys) }
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, sys: &dyn DynSystem) -> Expr {
Expr { location: self.pos.to_api(), clause: self.clause.into_api(sys) }
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: Expr, ctx: &SysCtx) -> Self {
pub fn from_api(api: api::Expr, ctx: &SysCtx) -> Self {
Self { pos: Pos::from_api(&api.location), clause: GenClause::from_api(api.clause, ctx) }
}
}
@@ -89,60 +95,59 @@ pub enum GenClause {
Seq(Box<GenExpr>, Box<GenExpr>),
Const(Tok<Vec<Tok<String>>>),
NewAtom(AtomFactory),
Atom(ExprTicket, Atom),
Bottom(ProjectErrorObj),
Atom(api::ExprTicket, api::Atom),
Bottom(Vec<OrcErr>),
}
impl GenClause {
pub fn to_api(&self, sys: &dyn DynSystem) -> Clause {
pub fn to_api(&self, ctx: SysCtx) -> api::Clause {
match self {
Self::Call(f, x) => Clause::Call(Box::new(f.to_api(sys)), Box::new(x.to_api(sys))),
Self::Seq(a, b) => Clause::Seq(Box::new(a.to_api(sys)), Box::new(b.to_api(sys))),
Self::Lambda(arg, body) => Clause::Lambda(*arg, Box::new(body.to_api(sys))),
Self::Arg(arg) => Clause::Arg(*arg),
Self::Const(name) => Clause::Const(name.marker()),
Self::Bottom(err) => Clause::Bottom(errv_to_apiv([err.clone()])),
Self::NewAtom(fac) => Clause::NewAtom(fac.clone().build(sys)),
Self::Atom(tk, atom) => Clause::Atom(*tk, atom.clone()),
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, sys: &dyn DynSystem) -> Clause {
pub fn into_api(self, ctx: SysCtx) -> api::Clause {
match self {
Self::Call(f, x) => Clause::Call(Box::new(f.into_api(sys)), Box::new(x.into_api(sys))),
Self::Seq(a, b) => Clause::Seq(Box::new(a.into_api(sys)), Box::new(b.into_api(sys))),
Self::Lambda(arg, body) => Clause::Lambda(arg, Box::new(body.into_api(sys))),
Self::Arg(arg) => Clause::Arg(arg),
Self::Slot(extk) => Clause::Slot(extk.handle.into_tk()),
Self::Const(name) => Clause::Const(name.marker()),
Self::Bottom(err) => Clause::Bottom(errv_to_apiv([err])),
Self::NewAtom(fac) => Clause::NewAtom(fac.clone().build(sys)),
Self::Atom(tk, atom) => Clause::Atom(tk, atom),
Self::Call(f, x) =>
api::Clause::Call(Box::new(f.into_api(ctx.clone())), Box::new(x.into_api(ctx))),
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: Clause, ctx: &SysCtx) -> Self {
pub fn from_api(api: api::Clause, ctx: &SysCtx) -> Self {
match api {
Clause::Arg(id) => Self::Arg(id),
Clause::Lambda(arg, body) => Self::Lambda(arg, Box::new(GenExpr::from_api(*body, ctx))),
Clause::NewAtom(_) => panic!("Clause::NewAtom should never be received, only sent"),
Clause::Bottom(s) => Self::Bottom(err_from_apiv(&s, &ctx.reqnot)),
Clause::Call(f, x) => Self::Call(
Box::new(GenExpr::from_api(*f, ctx)),
Box::new(GenExpr::from_api(*x, ctx)),
),
Clause::Seq(a, b) => Self::Seq(
Box::new(GenExpr::from_api(*a, ctx)),
Box::new(GenExpr::from_api(*b, ctx)),
),
Clause::Const(name) => Self::Const(deintern(name)),
Clause::Slot(exi) => Self::Slot(OwnedExpr::new(ExprHandle::from_args(ctx.clone(), exi))),
Clause::Atom(tk, atom) => Self::Atom(tk, atom),
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),
}
}
}
fn inherit(clause: GenClause) -> GenExpr { GenExpr { pos: Pos::Inherit, clause } }
pub fn sym_ref(path: Tok<Vec<Tok<String>>>) -> GenExpr { inherit(GenClause::Const(path)) }
pub fn atom<A: AtomicFeatures>(atom: A) -> GenExpr { inherit(GenClause::NewAtom(atom.factory())) }
pub fn atom<A: ToAtom>(atom: A) -> GenExpr { inherit(GenClause::NewAtom(atom.to_atom_factory())) }
pub fn seq(ops: impl IntoIterator<Item = GenExpr>) -> GenExpr {
fn recur(mut ops: impl Iterator<Item = GenExpr>) -> Option<GenExpr> {
@@ -169,5 +174,5 @@ pub fn call(v: impl IntoIterator<Item = GenExpr>) -> GenExpr {
.expect("Empty call expression")
}
pub fn bot<E: DynProjectError>(msg: E) -> GenExpr { inherit(GenClause::Bottom(Arc::new(msg))) }
pub fn bot_obj(e: ProjectErrorObj) -> GenExpr { inherit(GenClause::Bottom(e)) }
pub fn bot(e: OrcErr) -> GenExpr { botv(vec![e]) }
pub fn botv(ev: Vec<OrcErr>) -> GenExpr { inherit(GenClause::Bottom(ev)) }

View File

@@ -1,13 +1,13 @@
use std::num::NonZero;
use hashbrown::HashMap;
use orchid_api::error::ProjResult;
use orchid_api::vfs::{EagerVfs, Loaded, VfsId};
use orchid_base::interner::intern;
use orchid_base::name::PathSlice;
use crate::api;
pub trait VirtFS: Send + Sync + 'static {
fn load(&self, path: &PathSlice) -> ProjResult<Loaded>;
fn load(&self, path: &PathSlice) -> api::OrcResult<api::Loaded>;
}
pub enum DeclFs {
@@ -15,15 +15,15 @@ pub enum DeclFs {
Mod(&'static [(&'static str, DeclFs)]),
}
impl DeclFs {
pub fn to_api_rec(&self, vfses: &mut HashMap<VfsId, &'static dyn VirtFS>) -> EagerVfs {
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 = VfsId(NonZero::new(vfsc + 1).unwrap());
let id = api::VfsId(NonZero::new(vfsc + 1).unwrap());
vfses.insert(id, *fs);
EagerVfs::Lazy(id)
api::EagerVfs::Lazy(id)
},
DeclFs::Mod(children) => EagerVfs::Eager(
DeclFs::Mod(children) => api::EagerVfs::Eager(
children.iter().map(|(k, v)| (intern(*k).marker(), v.to_api_rec(vfses))).collect(),
),
}

View File

@@ -1,38 +0,0 @@
use std::borrow::Cow;
use dyn_clone::{clone_box, DynClone};
use never::Never;
use trait_set::trait_set;
use crate::atom::{Atomic, ReqPck};
use crate::atom_owned::{OwnedAtom, OwnedVariant};
use crate::conv::{ToExpr, TryFromExpr};
use crate::expr::{ExprHandle, GenExpr};
use crate::system::SysCtx;
trait_set! {
trait FunCB = FnOnce(ExprHandle) -> GenExpr + DynClone + Send + Sync + 'static;
}
pub struct Fun(Box<dyn FunCB>);
impl Fun {
pub fn new<I: TryFromExpr, O: ToExpr>(
f: impl FnOnce(I) -> O + Clone + Send + Sync + 'static,
) -> Self {
Self(Box::new(|eh| I::try_from_expr(eh).map(f).to_expr()))
}
}
impl Clone for Fun {
fn clone(&self) -> Self { Self(clone_box(&*self.0)) }
}
impl Atomic for Fun {
type Data = ();
type Req = Never;
type Variant = OwnedVariant;
}
impl OwnedAtom for Fun {
fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) }
fn call_ref(&self, arg: ExprHandle) -> GenExpr { self.clone().call(arg) }
fn call(self, arg: ExprHandle) -> GenExpr { (self.0)(arg) }
fn handle_req(&self, _ctx: SysCtx, pck: impl ReqPck<Self>) { pck.never() }
}

View File

@@ -0,0 +1,123 @@
use orchid_base::interner::Tok;
use std::borrow::Cow;
use std::collections::HashMap;
use std::io;
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::name::Sym;
use trait_set::trait_set;
use crate::atom::{Atomic, ReqPck};
use crate::atom_owned::{DeserializeCtx, OwnedAtom, OwnedVariant};
use crate::conv::ToExpr;
use crate::expr::{ExprHandle, GenExpr};
use crate::system::SysCtx;
trait_set! {
trait FunCB = Fn(Vec<ExprHandle>) -> OrcRes<GenExpr> + Send + Sync + 'static;
}
pub trait ExprFunc<I, O>: Clone + Send + Sync + 'static {
const ARITY: u8;
fn apply(&self, v: Vec<ExprHandle>) -> OrcRes<GenExpr>;
}
lazy_static!{
static ref FUNS: Mutex<HashMap<Sym, (u8, Arc<dyn FunCB>)>> = Mutex::default();
}
#[derive(Clone)]
pub(crate) struct Fun{
path: Sym,
args: Vec<ExprHandle>,
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 }
}
}
impl Atomic for Fun {
type Data = ();
type Req = Never;
type Variant = OwnedVariant;
}
impl OwnedAtom for Fun {
type Refs = Vec<ExprHandle>;
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();
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) -> GenExpr { self.call_ref(arg) }
fn handle_req(&self, pck: impl ReqPck<Self>) { pck.never() }
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 }
}
}
mod expr_func_derives {
use orchid_base::error::OrcRes;
use crate::func_atom::GenExpr;
use super::ExprFunc;
use crate::conv::{TryFromExpr, ToExpr};
use crate::func_atom::ExprHandle;
macro_rules! expr_func_derive {
($arity: tt, $($t:ident),*) => {
paste::paste!{
impl<
$($t: TryFromExpr, )*
Out: ToExpr,
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> {
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())
}
}
}
};
}
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,46 +1,44 @@
use std::ops::{Range, RangeInclusive};
use orchid_api::parser::{ParsId, SubLex};
use orchid_api::proto::ExtMsgSet;
use orchid_api::system::SysId;
use orchid_base::error::{mk_err, OrcErr, OrcRes};
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 crate::error::{
ProjectError, ProjectResult
};
use crate::api;
use crate::tree::{GenTok, GenTokTree};
pub struct CascadingError;
impl ProjectError for CascadingError {
const DESCRIPTION: &'static str = "An error cascading from a recursive sublexer";
fn message(&self) -> String {
"This error should not surface. If you are seeing it, something is wrong".to_string()
}
fn one_position(&self) -> Pos { Pos::None }
pub fn err_cascade() -> OrcErr {
mk_err(
intern!(str: "An error cascading from a recursive sublexer"),
"This error should not surface. If you are seeing it, something is wrong",
[Pos::None.into()],
)
}
pub struct NotApplicableLexerError;
impl ProjectError for NotApplicableLexerError {
const DESCRIPTION: &'static str = "Pseudo-error to communicate that the lexer doesn't apply";
fn message(&self) -> String { CascadingError.message() }
fn one_position(&self) -> Pos { Pos::None }
pub fn err_lexer_na() -> OrcErr {
mk_err(
intern!(str: "Pseudo-error to communicate that the lexer doesn't apply"),
&*err_cascade().message,
[Pos::None.into()],
)
}
pub struct LexContext<'a> {
pub text: &'a Tok<String>,
pub sys: SysId,
pub id: ParsId,
pub sys: api::SysId,
pub id: api::ParsId,
pub pos: u32,
pub reqnot: ReqNot<ExtMsgSet>,
pub reqnot: ReqNot<api::ExtMsgSet>,
}
impl<'a> LexContext<'a> {
pub fn recurse(&self, tail: &'a str) -> ProjectResult<(&'a str, GenTokTree)> {
pub fn recurse(&self, tail: &'a str) -> OrcRes<(&'a str, GenTokTree<'a>)> {
let start = self.pos(tail);
let lx = (self.reqnot.request(SubLex { pos: start, id: self.id }))
.ok_or_else(|| CascadingError.pack())?;
Ok((&self.text[lx.pos as usize..], GenTok::Slot(lx.ticket).at(start..lx.pos)))
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)))
}
pub fn pos(&self, tail: &'a str) -> u32 { (self.text.len() - tail.len()) as u32 }
@@ -52,19 +50,13 @@ impl<'a> LexContext<'a> {
pub trait Lexer: Send + Sync + Sized + Default + 'static {
const CHAR_FILTER: &'static [RangeInclusive<char>];
fn lex<'a>(
tail: &'a str,
ctx: &'a LexContext<'a>,
) -> ProjectResult<(&'a str, GenTokTree)>;
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>,
) -> ProjectResult<(&'a str, GenTokTree)>;
fn lex<'a>(&self, tail: &'a str, ctx: &'a LexContext<'a>)
-> OrcRes<(&'a str, GenTokTree<'a>)>;
}
impl<T: Lexer> DynLexer for T {
@@ -73,7 +65,7 @@ impl<T: Lexer> DynLexer for T {
&self,
tail: &'a str,
ctx: &'a LexContext<'a>,
) -> ProjectResult<(&'a str, GenTokTree)> {
) -> OrcRes<(&'a str, GenTokTree<'a>)> {
T::lex(tail, ctx)
}
}

View File

@@ -1,15 +1,18 @@
use orchid_api as api;
pub mod atom;
pub mod atom_owned;
pub mod atom_thin;
pub mod conv;
pub mod entrypoint;
pub mod error;
// pub mod error;
pub mod expr;
pub mod fs;
pub mod fun;
pub mod func_atom;
pub mod lexer;
pub mod msg;
pub mod other_system;
pub mod parser;
pub mod system;
pub mod system_ctor;
pub mod tree;

View File

@@ -1,24 +1,23 @@
use std::marker::PhantomData;
use std::mem::size_of;
use orchid_api::system::SysId;
use crate::api;
use crate::system::{DynSystemCard, SystemCard};
pub struct SystemHandle<C: SystemCard> {
pub(crate) _card: PhantomData<C>,
pub(crate) id: SysId,
pub(crate) id: api::SysId,
}
impl<C: SystemCard> SystemHandle<C> {
pub(crate) fn new(id: SysId) -> Self { Self { _card: PhantomData, id } }
pub fn id(&self) -> 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) }
}
pub trait DynSystemHandle {
fn id(&self) -> SysId;
fn id(&self) -> api::SysId;
fn get_card(&self) -> &dyn DynSystemCard;
}
@@ -32,6 +31,6 @@ pub fn leak_card<T: Default>() -> &'static T {
}
impl<C: SystemCard> DynSystemHandle for SystemHandle<C> {
fn id(&self) -> SysId { self.id }
fn id(&self) -> api::SysId { self.id }
fn get_card(&self) -> &'static dyn DynSystemCard { leak_card::<C>() }
}

View File

@@ -0,0 +1,24 @@
use orchid_base::error::OrcRes;
use orchid_base::parse::Snippet;
use crate::atom::{AtomFactory, ForeignAtom};
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(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>>>;
}
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) }
}
pub type ParserObj = &'static dyn DynParser;

View File

@@ -1,19 +1,20 @@
use std::any::TypeId;
use std::num::NonZero;
use std::sync::Arc;
use hashbrown::HashMap;
use orchid_api::atom::Atom;
use orchid_api::proto::ExtMsgSet;
use orchid_api::system::SysId;
use orchid_api::AtomId;
use orchid_api_traits::Decode;
use orchid_base::interner::Tok;
use orchid_base::logging::Logger;
use orchid_base::reqnot::ReqNot;
use crate::api;
use crate::atom::{get_info, AtomCtx, AtomDynfo, AtomicFeatures, ForeignAtom, TypAtom};
use crate::fs::DeclFs;
use crate::fun::Fun;
// use crate::fun::Fun;
use crate::lexer::LexerObj;
use crate::parser::ParserObj;
use crate::system_ctor::{CtedObj, SystemCtor};
use crate::tree::GenMemberKind;
@@ -33,31 +34,34 @@ pub trait DynSystemCard: Send + Sync + 'static {
/// 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() -> &'static [Option<&'static dyn AtomDynfo>] { &[/*Some(Fun::INFO)*/] }
pub fn atom_info_for(
sys: &(impl DynSystemCard + ?Sized),
tid: TypeId,
) -> Option<(u64, &'static dyn AtomDynfo)> {
(sys.atoms().iter().enumerate().map(|(i, o)| (i as u64, o)))
.chain(general_atoms().iter().enumerate().map(|(i, o)| (!(i as u64), o)))
.filter_map(|(i, o)| o.as_ref().map(|a| (i, *a)))
) -> 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)))
.find(|ent| ent.1.tid() == tid)
}
pub fn atom_by_idx(
sys: &(impl DynSystemCard + ?Sized),
tid: u64,
tid: api::AtomId,
) -> Option<&'static dyn AtomDynfo> {
if (tid >> (u64::BITS - 1)) & 1 == 1 {
general_atoms()[!tid as usize]
if (u64::from(tid.0) >> (u64::BITS - 1)) & 1 == 1 {
general_atoms()[!u64::from(tid.0) as usize]
} else {
sys.atoms()[tid as usize]
sys.atoms()[u64::from(tid.0) as usize - 1]
}
}
pub fn resolv_atom(sys: &(impl DynSystemCard + ?Sized), atom: &Atom) -> &'static dyn AtomDynfo {
let tid = u64::decode(&mut &atom.data[..8]);
pub fn resolv_atom(
sys: &(impl DynSystemCard + ?Sized),
atom: &api::Atom,
) -> &'static dyn AtomDynfo {
let tid = api::AtomId::decode(&mut &atom.data[..8]);
atom_by_idx(sys, tid).expect("Value of nonexistent type found")
}
@@ -71,32 +75,35 @@ pub trait System: Send + Sync + SystemCard + 'static {
fn env() -> Vec<(Tok<String>, GenMemberKind)>;
fn vfs() -> DeclFs;
fn lexers() -> Vec<LexerObj>;
fn parsers() -> Vec<ParserObj>;
}
pub trait DynSystem: Send + Sync + DynSystemCard + 'static {
fn dyn_env(&self) -> HashMap<Tok<String>, GenMemberKind>;
fn dyn_vfs(&self) -> DeclFs;
fn dyn_lexers(&self) -> Vec<LexerObj>;
fn dyn_card(&self) -> &dyn DynSystemCard;
fn dyn_parsers(&self) -> Vec<ParserObj>;
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_vfs(&self) -> DeclFs { Self::vfs() }
fn dyn_lexers(&self) -> Vec<LexerObj> { Self::lexers() }
fn dyn_card(&self) -> &dyn DynSystemCard { self }
fn dyn_parsers(&self) -> Vec<ParserObj> { Self::parsers() }
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.expr.get_ctx();
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, _)| u64::decode(&mut data) == *pos);
.filter(|(pos, _)| AtomId::decode(&mut data) == *pos);
match info_ent {
None => Err(foreign),
Some((_, info)) => {
let val = info.decode(AtomCtx(data, ctx));
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 })
},
@@ -105,8 +112,18 @@ pub fn downcast_atom<A: AtomicFeatures>(foreign: ForeignAtom) -> Result<TypAtom<
#[derive(Clone)]
pub struct SysCtx {
pub reqnot: ReqNot<ExtMsgSet>,
pub id: SysId,
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 }
}
}

View File

@@ -1,10 +1,10 @@
use std::any::Any;
use std::sync::Arc;
use orchid_api::system::{NewSystem, SysDeclId, SysId, SystemDecl};
use orchid_base::boxed_iter::{box_empty, box_once, BoxedIter};
use ordered_float::NotNan;
use crate::api;
use crate::other_system::{DynSystemHandle, SystemHandle};
use crate::system::{DynSystem, System, SystemCard};
@@ -34,7 +34,7 @@ pub trait DepSat: Clone + Send + Sync + 'static {
pub trait DepDef {
type Sat: DepSat;
fn report(names: &mut impl FnMut(&'static str));
fn create(take: &mut impl FnMut() -> SysId) -> Self::Sat;
fn create(take: &mut impl FnMut() -> api::SysId) -> Self::Sat;
}
impl<T: SystemCard> DepSat for SystemHandle<T> {
@@ -44,7 +44,7 @@ impl<T: SystemCard> DepSat for SystemHandle<T> {
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() -> SysId) -> Self::Sat { SystemHandle::new(take()) }
fn create(take: &mut impl FnMut() -> api::SysId) -> Self::Sat { SystemHandle::new(take()) }
}
impl DepSat for () {
@@ -53,7 +53,7 @@ impl DepSat for () {
impl DepDef for () {
type Sat = ();
fn create(_: &mut impl FnMut() -> SysId) -> Self::Sat {}
fn create(_: &mut impl FnMut() -> api::SysId) -> Self::Sat {}
fn report(_: &mut impl FnMut(&'static str)) {}
}
@@ -66,20 +66,20 @@ pub trait SystemCtor: Send + Sync + 'static {
}
pub trait DynSystemCtor: Send + Sync + 'static {
fn decl(&self, id: SysDeclId) -> SystemDecl;
fn new_system(&self, new: &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: SysDeclId) -> SystemDecl {
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()));
SystemDecl { name: T::NAME.to_string(), depends, id, priority }
api::SystemDecl { name: T::NAME.to_string(), depends, id, priority }
}
fn new_system(&self, NewSystem { system: _, id: _, depends }: &NewSystem) -> CtedObj {
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());
@@ -88,12 +88,12 @@ impl<T: SystemCtor> DynSystemCtor for T {
}
mod dep_set_tuple_impls {
use orchid_api::system::SysId;
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;
macro_rules! dep_set_tuple_impl {
@@ -126,7 +126,7 @@ mod dep_set_tuple_impls {
$name ::report(names);
)*
}
fn create(take: &mut impl FnMut() -> SysId) -> Self::Sat {
fn create(take: &mut impl FnMut() -> api::SysId) -> Self::Sat {
(
$(
$name ::create(take),

View File

@@ -1,183 +1,119 @@
use std::iter;
use std::num::NonZero;
use std::ops::Range;
use std::sync::Arc;
use hashbrown::HashMap;
use dyn_clone::{clone_box, DynClone};
use hashbrown::HashMap;
use itertools::Itertools;
use orchid_api::tree::{
Macro, Paren, PlaceholderKind, Token, TokenTree, Item, TreeId, ItemKind, Member, MemberKind, Module, TreeTicket
};
use orchid_base::interner::{intern, Tok};
use orchid_base::location::Pos;
use orchid_base::name::{NameLike, Sym, VName};
use orchid_base::tokens::OwnedPh;
use orchid_base::name::Sym;
use orchid_base::tree::{ttv_to_api, TokTree, Token};
use ordered_float::NotNan;
use substack::Substack;
use trait_set::trait_set;
use crate::atom::AtomFactory;
use crate::api;
use crate::atom::{AtomFactory, ForeignAtom};
use crate::conv::ToExpr;
use crate::entrypoint::MemberRecord;
use crate::error::{errv_to_apiv, ProjectErrorObj};
use crate::expr::GenExpr;
use crate::system::DynSystem;
use crate::func_atom::{ExprFunc, Fun};
use crate::system::SysCtx;
#[derive(Clone)]
pub struct GenTokTree {
pub tok: GenTok,
pub range: Range<u32>,
}
impl GenTokTree {
pub fn into_api(self, sys: &dyn DynSystem) -> TokenTree {
TokenTree { token: self.tok.into_api(sys), range: self.range }
}
}
pub type GenTokTree<'a> = TokTree<'a, ForeignAtom<'a>, AtomFactory>;
pub type GenTok<'a> = Token<'a, ForeignAtom<'a>, AtomFactory>;
pub fn ph(s: &str) -> OwnedPh {
match s.strip_prefix("..") {
Some(v_tail) => {
let (mid, priority) = match v_tail.split_once(':') {
Some((h, t)) => (h, t.parse().expect("priority not an u8")),
None => (v_tail, 0),
};
let (name, nonzero) = match mid.strip_prefix(".$") {
Some(name) => (name, true),
None => (mid.strip_prefix('$').expect("Invalid placeholder"), false),
};
if konst::string::starts_with(name, "_") {
panic!("Names starting with an underscore indicate a single-name scalar placeholder")
}
OwnedPh { name: intern(name), kind: PlaceholderKind::Vector { nz: nonzero, prio: priority } }
},
None => match konst::string::strip_prefix(s, "$_") {
Some(name) => OwnedPh { name: intern(name), kind: PlaceholderKind::Name },
None => match konst::string::strip_prefix(s, "$") {
None => panic!("Invalid placeholder"),
Some(name) => OwnedPh { name: intern(name), kind: PlaceholderKind::Scalar },
},
},
}
}
#[derive(Clone)]
pub enum GenTok {
Lambda(Vec<GenTokTree>),
Name(Tok<String>),
NS,
BR,
S(Paren, Vec<GenTokTree>),
Atom(AtomFactory),
Slot(TreeTicket),
Ph(OwnedPh),
Bottom(ProjectErrorObj),
}
impl GenTok {
pub fn at(self, range: Range<u32>) -> GenTokTree { GenTokTree { tok: self, range } }
pub fn into_api(self, sys: &dyn DynSystem) -> Token {
match self {
Self::Lambda(x) => Token::Lambda(x.into_iter().map(|tt| tt.into_api(sys)).collect()),
Self::Name(n) => Token::Name(n.marker()),
Self::NS => Token::NS,
Self::BR => Token::BR,
Self::Ph(ph) => Token::Ph(ph.to_api()),
Self::S(p, body) => Token::S(p, body.into_iter().map(|tt| tt.into_api(sys)).collect_vec()),
Self::Slot(tk) => Token::Slot(tk),
Self::Atom(at) => Token::Atom(at.build(sys)),
Self::Bottom(err) => Token::Bottom(errv_to_apiv([err])),
}
}
pub fn vname(name: &VName) -> impl Iterator<Item = GenTok> + '_ {
let (head, tail) = name.split_first();
iter::once(Self::Name(head)).chain(tail.iter().flat_map(|t| [Self::NS, Self::Name(t)]))
}
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)) }
}
#[derive(Clone)]
pub struct GenMacro {
pub pattern: Vec<GenTokTree>,
pub pattern: Vec<GenTokTree<'static>>,
pub priority: NotNan<f64>,
pub template: Vec<GenTokTree>,
}
pub fn tokv_into_api(
tokv: impl IntoIterator<Item = GenTokTree>,
sys: &dyn DynSystem,
) -> Vec<TokenTree> {
tokv.into_iter().map(|tok| tok.into_api(sys)).collect_vec()
}
pub fn wrap_tokv(items: Vec<GenTokTree>, range: Range<u32>) -> GenTokTree {
match items.len() {
1 => items.into_iter().next().unwrap(),
_ => GenTok::S(Paren::Round, items).at(range),
}
pub template: Vec<GenTokTree<'static>>,
}
pub struct GenItem {
pub item: GenItemKind,
pub comments: Vec<(String, Pos)>,
pub pos: Pos,
}
impl GenItem {
pub fn into_api(self, ctx: &mut impl TreeIntoApiCtx) -> Item {
pub fn into_api(self, ctx: &mut impl TreeIntoApiCtx) -> api::Item {
let kind = match self.item {
GenItemKind::Rule(GenMacro { pattern, priority, template }) => ItemKind::Rule(Macro {
pattern: tokv_into_api(pattern, ctx.sys()),
priority,
template: tokv_into_api(template, ctx.sys()),
GenItemKind::Rule(m) => api::ItemKind::Rule(api::Macro {
pattern: ttv_to_api(m.pattern, &mut |f, r| do_extra(f, r, ctx.sys())),
priority: m.priority,
template: ttv_to_api(m.template, &mut |f, r| do_extra(f, r, ctx.sys())),
}),
GenItemKind::Raw(item) => ItemKind::Raw(item.into_iter().map(|t| t.into_api(ctx.sys())).collect_vec()),
GenItemKind::Member(mem) => ItemKind::Member(mem.into_api(ctx))
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()))),
)),
GenItemKind::Member(mem) => api::ItemKind::Member(mem.into_api(ctx)),
};
Item { location: self.pos.to_api(), kind }
let comments = self.comments.into_iter().map(|(s, p)| (Arc::new(s), p.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 { public, name: intern(name), kind }).at(Pos::Inherit)
GenItemKind::Member(GenMember { exported: public, name: intern(name), kind }).at(Pos::Inherit)
}
pub fn module(
public: bool,
name: &str,
imports: impl IntoIterator<Item = Sym>,
items: impl IntoIterator<Item = GenItem>
items: impl IntoIterator<Item = GenItem>,
) -> GenItem {
let (name, kind) = root_mod(name, imports, items);
GenItemKind::Member(GenMember { public, name, kind }).at(Pos::Inherit)
GenItemKind::Member(GenMember { exported: public, name, kind }).at(Pos::Inherit)
}
pub fn root_mod(
name: &str,
name: &str,
imports: impl IntoIterator<Item = Sym>,
items: impl IntoIterator<Item = GenItem>
items: impl IntoIterator<Item = GenItem>,
) -> (Tok<String>, GenMemberKind) {
let kind = GenMemberKind::Mod {
imports: imports.into_iter().collect(),
items: items.into_iter().collect()
items: items.into_iter().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 rule(
prio: f64,
pat: impl IntoIterator<Item = GenTokTree>,
tpl: impl IntoIterator<Item = GenTokTree>,
priority: f64,
pat: impl IntoIterator<Item = GenTokTree<'static>>,
tpl: impl IntoIterator<Item = GenTokTree<'static>>,
) -> GenItem {
GenItemKind::Rule(GenMacro {
pattern: pat.into_iter().collect(),
priority: NotNan::new(prio).expect("expected to be static"),
priority: NotNan::new(priority).expect("Rule created with NaN prio"),
template: tpl.into_iter().collect(),
})
.at(Pos::Inherit)
}
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)));
val
}
trait_set! {
trait LazyMemberCallback = FnOnce() -> GenMemberKind + Send + Sync + DynClone
trait LazyMemberCallback = FnOnce(Sym) -> GenMemberKind + Send + Sync + DynClone
}
pub struct LazyMemberFactory(Box<dyn LazyMemberCallback>);
impl LazyMemberFactory {
pub fn new(cb: impl FnOnce() -> GenMemberKind + Send + Sync + Clone + 'static) -> Self {
pub fn new(cb: impl FnOnce(Sym) -> GenMemberKind + Send + Sync + Clone + 'static) -> Self {
Self(Box::new(cb))
}
pub fn build(self) -> GenMemberKind { (self.0)() }
pub fn build(self, path: Sym) -> GenMemberKind { (self.0)(path) }
}
impl Clone for LazyMemberFactory {
fn clone(&self) -> Self { Self(clone_box(&*self.0)) }
@@ -185,60 +121,75 @@ impl Clone for LazyMemberFactory {
pub enum GenItemKind {
Member(GenMember),
Raw(Vec<GenTokTree>),
Raw(Vec<GenTokTree<'static>>),
Rule(GenMacro),
}
impl GenItemKind {
pub fn at(self, position: Pos) -> GenItem { GenItem { item: self, pos: position } }
pub fn at(self, position: Pos) -> GenItem {
GenItem { item: self, comments: vec![], pos: position }
}
}
pub struct GenMember {
public: bool,
exported: bool,
name: Tok<String>,
kind: GenMemberKind,
}
impl GenMember {
pub fn into_api(self, ctx: &mut impl TreeIntoApiCtx) -> Member {
Member { name: self.name.marker(), public: self.public, kind: self.kind.into_api(ctx) }
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),
Mod{
imports: Vec<Sym>,
items: Vec<GenItem>,
},
Lazy(LazyMemberFactory)
Mod { imports: Vec<Sym>, items: Vec<GenItem> },
Lazy(LazyMemberFactory),
}
impl GenMemberKind {
pub fn into_api(self, ctx: &mut impl TreeIntoApiCtx) -> MemberKind {
pub fn into_api(self, ctx: &mut impl TreeIntoApiCtx) -> api::MemberKind {
match self {
Self::Lazy(lazy) => MemberKind::Lazy(ctx.with_lazy(lazy)),
Self::Const(c) => MemberKind::Const(c.into_api(ctx.sys())),
Self::Mod { imports, items } => MemberKind::Module(Module {
Self::Lazy(lazy) => api::MemberKind::Lazy(ctx.with_lazy(lazy)),
Self::Const(c) => api::MemberKind::Const(c.into_api(ctx.sys())),
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: items.into_iter().map(|i| i.into_api(ctx)).collect_vec(),
}),
}
}
}
pub trait TreeIntoApiCtx {
fn sys(&self) -> &dyn DynSystem;
fn with_lazy(&mut self, fac: LazyMemberFactory) -> TreeId;
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> {
pub sys: &'a dyn DynSystem,
pub lazy: &'a mut HashMap<TreeId, MemberRecord>
pub struct TIACtxImpl<'a, 'b> {
pub ctx: SysCtx,
pub basepath: &'a [Tok<String>],
pub path: Substack<'a, Tok<String>>,
pub lazy: &'b mut HashMap<api::TreeId, MemberRecord>,
}
impl<'a> TreeIntoApiCtx for TIACtxImpl<'a> {
fn sys(&self) -> &dyn DynSystem { self.sys }
fn with_lazy(&mut self, fac: LazyMemberFactory) -> TreeId {
let id = TreeId(NonZero::new((self.lazy.len() + 2) as u64).unwrap());
self.lazy.insert(id, MemberRecord::Gen(fac));
impl<'a, 'b> TreeIntoApiCtx for TIACtxImpl<'a, 'b> {
fn sys(&self) -> SysCtx { self.ctx.clone() }
fn push_path(&mut self, seg: Tok<String>) -> impl TreeIntoApiCtx {
TIACtxImpl {
ctx: self.ctx.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
}
}