Cleaned up atoms

- Atoms now use MFBI to distinguish between thin and owned atoms.
- Introduced TryFromExpr and ToExpr (formerly ToClause) from the old FFI
- Standardized on Bottom being a ProjErr, which means that there will be no RTErr
This commit is contained in:
2024-07-02 00:57:11 +02:00
parent fc8441f080
commit 949b3758fd
25 changed files with 383 additions and 297 deletions

2
Cargo.lock generated
View File

@@ -326,6 +326,7 @@ dependencies = [
"itertools", "itertools",
"konst", "konst",
"never", "never",
"once_cell",
"orchid-api", "orchid-api",
"orchid-api-derive", "orchid-api-derive",
"orchid-api-traits", "orchid-api-traits",
@@ -356,6 +357,7 @@ name = "orchid-std"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"itertools", "itertools",
"once_cell",
"orchid-api", "orchid-api",
"orchid-api-derive", "orchid-api-derive",
"orchid-api-traits", "orchid-api-traits",

37
notes/crates.md Normal file
View File

@@ -0,0 +1,37 @@
The role and relations of the crates in this monorepo
# orcx
Reference runtime built using [`orchid-host`](#orchid-host)
# orchid-std
Standard library and reference extension built using [`orchid-extension`](#orchid-extension)
# orchid-host
Interpreter library with extension host. This is built to support embedding in arbitrary host applications for scripting, although it is not security hardened.
# orchid-extension
Extension development toolkit. It routes the requests to handlers in a nice object model, and manages resources like `ExprTicket`.
# orchid-base
Common items used by both [`orchid-host`](#orchid-host) and [`orchid-extension`](#orchid-extension). Most notably, both sides of the string interner are defined here because it has to be callable from other items defined in this crate through the same set of global functions in both environments.
# orchid-api
Definition of the extension API. This crate should not contain any logic, it should hold only serializable message structs, and their relations should represent how they fit into the protocol.
# orchid-api-derive
Derive macros for the traits in [`orchid-api-traits`](#orchid-api-traits) to make the definitions in [`orchid-api`](#orchid-api) more concise.
# orchid-api-traits
Traits with a semantic meaning with respect to the protocol elements defined in [`orchid-api`](#orchid-api):
- `Encode`, `Decode` and `Coding` define how types serialize.
- `Request` associates requests with their response types.
- `InHierarchy`, `Extends` and `UnderRoot` associate requests and notifications with the category hierarchy they belong to.

View File

@@ -1,30 +0,0 @@
pub trait TBool {}
pub struct TTrue;
impl TBool for TTrue {}
pub struct TFalse;
impl TBool for TFalse {}
/// Implementation picker for a tree node
///
/// Note: This technically allows for the degenerate case
/// ```
/// struct MyType;
/// impl TreeRolePicker for MyType {
/// type IsLeaf = TTrue;
/// type IsRoot = TTrue;
/// }
/// ```
/// This isn't very useful because it describes a one element sealed hierarchy.
pub trait TreeRolePicker {
type IsLeaf: TBool;
type IsRoot: TBool;
}
pub trait Extends: TreeRolePicker<IsRoot = TFalse> {
type Parent: TreeRolePicker<IsLeaf = TFalse>;
}
pub trait Inherits<T> {}
// impl<T> Inherits<T, 0> for T {}
impl<T: Extends, This> Inherits<T::Parent> for This where This: Inherits<T> {}

View File

@@ -1,8 +1,3 @@
/// [Hierarchy] implementation key. The two implementors of this trait are
/// [Base] and [Subtype]. These types are assigned to [InHierarchy::Role] to
/// select the implementation of [Hierarchy].
pub trait HierarchyRole {}
/// A type-level boolean suitable to select conditional trait implementations. /// A type-level boolean suitable to select conditional trait implementations.
/// Implementors are [True] and [False] /// Implementors are [True] and [False]
pub trait TLBool {} pub trait TLBool {}
@@ -13,17 +8,6 @@ impl TLBool for TLTrue {}
pub struct TLFalse; pub struct TLFalse;
impl TLBool for TLFalse {} impl TLBool for TLFalse {}
/// Assign this type to [InHierarchy::Role] and implement [Descendant] to create
/// a subtype. These types can be upcast to their parent type, conditionally
/// downcast from it, and selected for [Descendant::Parent] by other types.
pub struct Subtype;
impl HierarchyRole for Subtype {}
/// Assign this type to [InHierarchy::Role] to create a base type. These types
/// are upcast only to themselves, but they can be selected in
/// [Descendant::Parent].
pub struct Base;
impl HierarchyRole for Base {}
/// A type that implements [Hierarchy]. Used to select implementations of traits /// A type that implements [Hierarchy]. Used to select implementations of traits
/// on the hierarchy /// on the hierarchy
pub trait InHierarchy: Clone { pub trait InHierarchy: Clone {

View File

@@ -6,7 +6,6 @@ mod relations;
pub use coding::{Coding, Decode, Encode}; pub use coding::{Coding, Decode, Encode};
pub use helpers::{encode_enum, read_exact, write_exact}; pub use helpers::{encode_enum, read_exact, write_exact};
pub use hierarchy::{ pub use hierarchy::{
Base, Extends, HierarchyRole, InHierarchy, Subtype, TLBool, TLFalse, TLTrue, UnderRoot, Extends, InHierarchy, TLBool, TLFalse, TLTrue, UnderRoot,
UnderRootImpl,
}; };
pub use relations::{Channel, MsgSet, Request}; pub use relations::{Channel, MsgSet, Request};

View File

@@ -4,6 +4,7 @@ use orchid_api_derive::{Coding, Hierarchy};
use orchid_api_traits::Request; use orchid_api_traits::Request;
use crate::atom::{Atom, LocalAtom}; use crate::atom::{Atom, LocalAtom};
use crate::error::ProjErr;
use crate::interner::TStrv; use crate::interner::TStrv;
use crate::location::Location; use crate::location::Location;
use crate::proto::{ExtHostNotif, ExtHostReq}; use crate::proto::{ExtHostNotif, ExtHostReq};
@@ -83,7 +84,7 @@ pub enum Clause {
/// A reference to a constant /// A reference to a constant
Const(TStrv), Const(TStrv),
/// A static runtime error. /// A static runtime error.
Bottom(String), Bottom(ProjErr),
} }
#[derive(Clone, Debug, Coding)] #[derive(Clone, Debug, Coding)]

View File

@@ -13,6 +13,7 @@ hashbrown = "0.14.5"
itertools = "0.13.0" itertools = "0.13.0"
konst = "0.3.9" konst = "0.3.9"
never = "0.1.0" never = "0.1.0"
once_cell = "1.19.0"
orchid-api = { version = "0.1.0", path = "../orchid-api" } orchid-api = { version = "0.1.0", path = "../orchid-api" }
orchid-api-derive = { version = "0.1.0", path = "../orchid-api-derive" } orchid-api-derive = { version = "0.1.0", path = "../orchid-api-derive" }
orchid-api-traits = { version = "0.1.0", path = "../orchid-api-traits" } orchid-api-traits = { version = "0.1.0", path = "../orchid-api-traits" }

View File

@@ -1,75 +1,60 @@
use std::any::{type_name, Any}; use std::any::{type_name, Any};
use std::borrow::Cow;
use std::fmt;
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::num::NonZeroU64;
use std::ops::Deref; use std::ops::Deref;
use dyn_clone::{clone_box, DynClone}; use dyn_clone::{clone_box, DynClone};
use orchid_api::atom::{Atom, Fwd, LocalAtom}; use orchid_api::atom::{Atom, Fwd, LocalAtom};
use orchid_api::expr::ExprTicket; use orchid_api::expr::ExprTicket;
use orchid_api::system::SysId; use orchid_api_traits::{Coding, Decode, Request};
use orchid_api_traits::{Coding, Decode, Encode, Request};
use orchid_base::id_store::{IdRecord, IdStore};
use orchid_base::location::Pos; use orchid_base::location::Pos;
use orchid_base::reqnot::Requester; use orchid_base::reqnot::Requester;
use trait_set::trait_set; use trait_set::trait_set;
use typeid::ConstTypeId; use typeid::ConstTypeId;
use crate::expr::{bot, ExprHandle, GenClause}; use crate::error::ProjectError;
use crate::expr::{ExprHandle, GenExpr};
use crate::system::{atom_info_for, DynSystem, DynSystemCard, SysCtx}; use crate::system::{atom_info_for, DynSystem, DynSystemCard, SysCtx};
pub trait AtomCard: 'static + Sized { pub trait AtomCard: 'static + Sized {
// type Owner: SystemCard;
type Data: Clone + Coding + Sized; type Data: Clone + Coding + Sized;
type Req: Coding; type Req: Coding;
} }
pub trait AtomicVariant {}
pub trait Atomic: 'static + Sized {
type Variant: AtomicVariant;
type Data: Clone + Coding + Sized;
type Req: Coding;
}
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;
fn info() -> &'static AtomInfo;
}
pub trait AtomicFeaturesImpl<Variant: AtomicVariant> {
fn _factory(self) -> AtomFactory;
fn _info() -> &'static AtomInfo;
}
impl<A: Atomic + AtomicFeaturesImpl<A::Variant>> AtomicFeatures for A {
fn factory(self) -> AtomFactory { self._factory() }
fn info() -> &'static AtomInfo { Self::_info() }
}
pub fn get_info<A: AtomCard>(sys: &(impl DynSystemCard + ?Sized)) -> (u64, &AtomInfo) { pub fn get_info<A: AtomCard>(sys: &(impl DynSystemCard + ?Sized)) -> (u64, &AtomInfo) {
atom_info_for(sys, ConstTypeId::of::<A>()).unwrap_or_else(|| { atom_info_for(sys, ConstTypeId::of::<A>()).unwrap_or_else(|| {
panic!("Atom {} not associated with system {}", type_name::<A>(), sys.name()) panic!("Atom {} not associated with system {}", type_name::<A>(), sys.name())
}) })
} }
pub fn encode_atom_nodrop<A: AtomCard>(
sys: &(impl DynSystemCard + ?Sized),
data: &A::Data,
) -> LocalAtom {
let mut buf = get_info::<A>(sys).0.enc_vec();
data.encode(&mut buf);
LocalAtom { drop: false, data: buf }
}
pub fn encode_atom_drop<A: AtomCard>(
sys_id: SysId,
sys: &(impl DynSystemCard + ?Sized),
atom_id: u64,
data: &A::Data,
) -> Atom {
let mut buf = get_info::<A>(sys).0.enc_vec();
atom_id.encode(&mut buf);
data.encode(&mut buf);
Atom { owner: sys_id, drop: true, data: buf }
}
pub fn decode_atom<A: AtomCard>(
sys: &(impl DynSystemCard + ?Sized),
Atom { data, drop: _, owner: _ }: &Atom,
) -> Option<A::Data> {
let (info_pos, info) = get_info::<A>(sys);
let mut data = &data[..];
if u64::decode(&mut data) != info_pos {
return None;
}
let val = (info.decode)(data);
Some(*val.downcast().expect("The type-id checked out, the decode should've worked"))
}
#[derive(Clone)] #[derive(Clone)]
pub struct ForeignAtom { pub struct ForeignAtom {
pub expr: ExprHandle, pub expr: ExprHandle,
pub atom: Atom, pub atom: Atom,
pub position: Pos, pub pos: Pos,
} }
impl ForeignAtom {} impl ForeignAtom {}
@@ -93,126 +78,13 @@ impl<A: AtomCard> Deref for TypAtom<A> {
pub struct AtomInfo { pub struct AtomInfo {
pub tid: ConstTypeId, pub tid: ConstTypeId,
pub decode: fn(&[u8]) -> Box<dyn Any>, pub decode: fn(&[u8]) -> Box<dyn Any>,
pub call: fn(&[u8], SysCtx, ExprTicket) -> GenClause, pub call: fn(&[u8], SysCtx, ExprTicket) -> GenExpr,
pub call_ref: fn(&[u8], SysCtx, ExprTicket) -> GenClause, pub call_ref: fn(&[u8], SysCtx, ExprTicket) -> GenExpr,
pub same: fn(&[u8], SysCtx, &[u8]) -> bool, pub same: fn(&[u8], SysCtx, &[u8]) -> bool,
pub handle_req: fn(&[u8], SysCtx, &mut dyn Read, &mut dyn Write), pub handle_req: fn(&[u8], SysCtx, &mut dyn Read, &mut dyn Write),
pub drop: fn(&[u8], SysCtx), pub drop: fn(&[u8], SysCtx),
} }
pub trait ThinAtom: AtomCard<Data = Self> + Coding + fmt::Debug {
#[allow(unused_variables)]
fn call(&self, arg: ExprHandle) -> GenClause { bot("This atom is not callable") }
#[allow(unused_variables)]
fn same(&self, ctx: SysCtx, other: &Self) -> bool {
eprintln!(
"Override ThinAtom::same for {} if it can be generated during parsing",
type_name::<Self>()
);
false
}
fn handle_req(&self, ctx: SysCtx, req: Self::Req, rep: &mut (impl Write + ?Sized));
fn factory(self) -> AtomFactory {
AtomFactory::new(move |sys| encode_atom_nodrop::<Self>(sys.dyn_card(), &self))
}
}
pub const fn thin_atom_info<T: ThinAtom>() -> AtomInfo {
AtomInfo {
tid: ConstTypeId::of::<T>(),
decode: |mut b| Box::new(T::decode(&mut b)),
call: |mut b, ctx, extk| T::decode(&mut b).call(ExprHandle::from_args(ctx, extk)),
call_ref: |mut b, ctx, extk| T::decode(&mut b).call(ExprHandle::from_args(ctx, extk)),
handle_req: |mut b, ctx, req, rep| T::decode(&mut b).handle_req(ctx, Decode::decode(req), rep),
same: |mut b1, ctx, mut b2| T::decode(&mut b1).same(ctx, &T::decode(&mut b2)),
drop: |mut b1, _| eprintln!("Received drop signal for non-drop atom {:?}", T::decode(&mut b1)),
}
}
/// Atoms that have a [Drop]
pub trait OwnedAtom: AtomCard + Send + Sync + Any + Clone + 'static {
fn val(&self) -> Cow<'_, Self::Data>;
#[allow(unused_variables)]
fn call_ref(&self, arg: ExprHandle) -> GenClause { bot("This atom is not callable") }
fn call(self, arg: ExprHandle) -> GenClause {
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 {
eprintln!(
"Override OwnedAtom::same for {} if it can be generated during parsing",
type_name::<Self>()
);
false
}
fn handle_req(&self, ctx: SysCtx, req: Self::Req, rep: &mut (impl Write + ?Sized));
#[allow(unused_variables)]
fn free(self, ctx: SysCtx) {}
#[allow(unused_variables)]
fn factory(self) -> AtomFactory {
AtomFactory::new(move |sys| {
let rec = OBJ_STORE.add(Box::new(self));
let mut data = atom_info_for(sys.dyn_card(), rec.atom_tid()).expect("obj exists").0.enc_vec();
rec.id().encode(&mut data);
rec.encode(&mut data);
LocalAtom { drop: true, data }
})
}
}
pub trait DynOwnedAtom: Send + Sync + 'static {
fn atom_tid(&self) -> ConstTypeId;
fn as_any_ref(&self) -> &dyn Any;
fn encode(&self, buffer: &mut dyn Write);
fn dyn_call_ref(&self, ctx: SysCtx, arg: ExprTicket) -> GenClause;
fn dyn_call(self: Box<Self>, ctx: SysCtx, arg: ExprTicket) -> GenClause;
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_free(self: Box<Self>, ctx: SysCtx);
}
impl<T: OwnedAtom> DynOwnedAtom for T {
fn atom_tid(&self) -> ConstTypeId { ConstTypeId::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) -> GenClause {
self.call_ref(ExprHandle::from_args(ctx, arg))
}
fn dyn_call(self: Box<Self>, ctx: SysCtx, arg: ExprTicket) -> GenClause {
self.call(ExprHandle::from_args(ctx, arg))
}
fn dyn_same(&self, ctx: SysCtx, other: &dyn DynOwnedAtom) -> bool {
if ConstTypeId::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, ctx: SysCtx, req: &mut dyn Read, rep: &mut dyn Write) {
self.handle_req(ctx, <Self as AtomCard>::Req::decode(req), rep)
}
fn dyn_free(self: Box<Self>, ctx: SysCtx) { self.free(ctx) }
}
pub(crate) static OBJ_STORE: IdStore<Box<dyn DynOwnedAtom>> = IdStore::new();
pub const fn owned_atom_info<T: OwnedAtom>() -> AtomInfo {
fn with_atom<U>(mut b: &[u8], f: impl FnOnce(IdRecord<'_, Box<dyn DynOwnedAtom>>) -> U) -> U {
f(OBJ_STORE.get(NonZeroU64::decode(&mut b)).expect("Received invalid atom ID"))
}
AtomInfo {
tid: ConstTypeId::of::<T>(),
decode: |mut b| Box::new(T::Data::decode(&mut b)),
call: |b, ctx, arg| with_atom(b, |a| a.remove().dyn_call(ctx, arg)),
call_ref: |b, ctx, arg| with_atom(b, |a| a.dyn_call_ref(ctx, arg)),
same: |b1, ctx, b2| with_atom(b1, |a1| with_atom(b2, |a2| a1.dyn_same(ctx, &**a2))),
handle_req: |b, ctx, req, rep| with_atom(b, |a| a.dyn_handle_req(ctx, req, rep)),
drop: |b, ctx| with_atom(b, |a| a.remove().dyn_free(ctx)),
}
}
trait_set! { trait_set! {
pub trait AtomFactoryFn = FnOnce(&dyn DynSystem) -> LocalAtom + DynClone; pub trait AtomFactoryFn = FnOnce(&dyn DynSystem) -> LocalAtom + DynClone;
} }
@@ -226,3 +98,8 @@ impl AtomFactory {
impl Clone for AtomFactory { impl Clone for AtomFactory {
fn clone(&self) -> Self { AtomFactory(clone_box(&*self.0)) } fn clone(&self) -> Self { AtomFactory(clone_box(&*self.0)) }
} }
pub struct ErrorNotCallable;
impl ProjectError for ErrorNotCallable {
const DESCRIPTION: &'static str = "This atom is not callable";
}

View File

@@ -0,0 +1,96 @@
use std::{any::{type_name, Any}, borrow::Cow, io::{Read, Write}, num::NonZeroU64};
use orchid_api::{atom::LocalAtom, expr::ExprTicket};
use orchid_api_traits::{Decode, Encode};
use orchid_base::id_store::{IdRecord, IdStore};
use typeid::ConstTypeId;
use crate::{atom::{AtomCard, AtomFactory, AtomInfo, Atomic, AtomicFeaturesImpl, AtomicVariant, ErrorNotCallable}, expr::{bot, ExprHandle, GenExpr}, system::{atom_info_for, SysCtx}};
pub struct OwnedVariant;
impl AtomicVariant for OwnedVariant {}
impl<A: OwnedAtom + Atomic<Variant = OwnedVariant>> AtomicFeaturesImpl<OwnedVariant> for A {
fn _factory(self) -> AtomFactory {
AtomFactory::new(move |sys| {
let rec = OBJ_STORE.add(Box::new(self));
let mut data = atom_info_for(sys.dyn_card(), rec.atom_tid()).expect("obj exists").0.enc_vec();
rec.id().encode(&mut data);
rec.encode(&mut data);
LocalAtom { drop: true, data }
})
}
fn _info() -> &'static AtomInfo {
fn with_atom<U>(mut b: &[u8], f: impl FnOnce(IdRecord<'_, Box<dyn DynOwnedAtom>>) -> U) -> U {
f(OBJ_STORE.get(NonZeroU64::decode(&mut b)).expect("Received invalid atom ID"))
}
&const {
AtomInfo {
tid: ConstTypeId::of::<Self>(),
decode: |mut b| Box::new(<Self as Atomic>::Data::decode(&mut b)),
call: |b, ctx, arg| with_atom(b, |a| a.remove().dyn_call(ctx, arg)),
call_ref: |b, ctx, arg| with_atom(b, |a| a.dyn_call_ref(ctx, arg)),
same: |b1, ctx, b2| with_atom(b1, |a1| with_atom(b2, |a2| a1.dyn_same(ctx, &**a2))),
handle_req: |b, ctx, req, rep| with_atom(b, |a| a.dyn_handle_req(ctx, req, rep)),
drop: |b, ctx| with_atom(b, |a| a.remove().dyn_free(ctx)),
}
}
}
}
/// Atoms that have a [Drop]
pub trait OwnedAtom: AtomCard + Send + Sync + Any + Clone + 'static {
fn val(&self) -> Cow<'_, Self::Data>;
#[allow(unused_variables)]
fn call_ref(&self, arg: ExprHandle) -> GenExpr { bot(ErrorNotCallable) }
fn call(self, arg: ExprHandle) -> GenExpr {
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 {
eprintln!(
"Override OwnedAtom::same for {} if it can be generated during parsing",
type_name::<Self>()
);
false
}
fn handle_req(&self, ctx: SysCtx, req: Self::Req, rep: &mut (impl Write + ?Sized));
#[allow(unused_variables)]
fn free(self, ctx: SysCtx) {}
}
pub trait DynOwnedAtom: Send + Sync + 'static {
fn atom_tid(&self) -> ConstTypeId;
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_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_free(self: Box<Self>, ctx: SysCtx);
}
impl<T: OwnedAtom> DynOwnedAtom for T {
fn atom_tid(&self) -> ConstTypeId { ConstTypeId::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 {
self.call_ref(ExprHandle::from_args(ctx, arg))
}
fn dyn_call(self: Box<Self>, ctx: SysCtx, arg: ExprTicket) -> GenExpr {
self.call(ExprHandle::from_args(ctx, arg))
}
fn dyn_same(&self, ctx: SysCtx, other: &dyn DynOwnedAtom) -> bool {
if ConstTypeId::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, ctx: SysCtx, req: &mut dyn Read, rep: &mut dyn Write) {
self.handle_req(ctx, <Self as AtomCard>::Req::decode(req), rep)
}
fn dyn_free(self: Box<Self>, ctx: SysCtx) { self.free(ctx) }
}
pub(crate) static OBJ_STORE: IdStore<Box<dyn DynOwnedAtom>> = IdStore::new();

View File

@@ -0,0 +1,46 @@
use std::{any::type_name, fmt, io::Write};
use orchid_api::atom::LocalAtom;
use orchid_api_traits::{Coding, Decode, Encode};
use typeid::ConstTypeId;
use crate::{atom::{get_info, AtomCard, AtomFactory, AtomInfo, Atomic, AtomicFeaturesImpl, AtomicVariant, ErrorNotCallable}, expr::{bot, ExprHandle, GenExpr}, system::SysCtx};
pub struct ThinVariant;
impl AtomicVariant for ThinVariant {}
impl<A: ThinAtom + Atomic<Variant = ThinVariant>> AtomicFeaturesImpl<ThinVariant> for A {
fn _factory(self) -> AtomFactory {
AtomFactory::new(move |sys| {
let mut buf = get_info::<A>(sys.dyn_card()).0.enc_vec();
self.encode(&mut buf);
LocalAtom { drop: false, data: buf }
})
}
fn _info() -> &'static AtomInfo {
&const {
AtomInfo {
tid: ConstTypeId::of::<Self>(),
decode: |mut b| Box::new(Self::decode(&mut b)),
call: |mut b, ctx, extk| Self::decode(&mut b).call(ExprHandle::from_args(ctx, extk)),
call_ref: |mut b, ctx, extk| Self::decode(&mut b).call(ExprHandle::from_args(ctx, extk)),
handle_req: |mut b, ctx, req, rep| Self::decode(&mut b).handle_req(ctx, Decode::decode(req), rep),
same: |mut b1, ctx, mut b2| Self::decode(&mut b1).same(ctx, &Self::decode(&mut b2)),
drop: |mut b1, _| eprintln!("Received drop signal for non-drop atom {:?}", Self::decode(&mut b1)),
}
}
}
}
pub trait ThinAtom: AtomCard<Data = Self> + Coding + fmt::Debug {
#[allow(unused_variables)]
fn call(&self, arg: ExprHandle) -> GenExpr { bot(ErrorNotCallable) }
#[allow(unused_variables)]
fn same(&self, ctx: SysCtx, other: &Self) -> bool {
eprintln!(
"Override ThinAtom::same for {} if it can be generated during parsing",
type_name::<Self>()
);
false
}
fn handle_req(&self, ctx: SysCtx, req: Self::Req, rep: &mut (impl Write + ?Sized));
}

View File

@@ -0,0 +1,55 @@
use orchid_base::location::Pos;
use crate::{atom::{AtomicFeatures, TypAtom}, error::{ProjectError, ProjectResult}, expr::{atom, bot_obj, ExprHandle, GenExpr, OwnedExpr}, system::downcast_atom};
pub trait TryFromExpr: Sized {
fn try_from_expr(expr: ExprHandle) -> ProjectResult<Self>;
}
impl TryFromExpr for OwnedExpr {
fn try_from_expr(expr: ExprHandle) -> ProjectResult<Self> { Ok(OwnedExpr::new(expr)) }
}
impl<T: TryFromExpr, U: TryFromExpr> TryFromExpr for (T, U) {
fn try_from_expr(expr: ExprHandle) -> ProjectResult<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() }
}
pub struct ErrorUnexpectedType(Pos);
impl ProjectError for ErrorUnexpectedType {
const DESCRIPTION: &'static str = "Type error";
fn one_position(&self) -> Pos {
self.0.clone()
}
}
impl<A: AtomicFeatures> TryFromExpr for TypAtom<A> {
fn try_from_expr(expr: ExprHandle) -> ProjectResult<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()))
}
}
pub trait ToExpr {
fn to_expr(self) -> GenExpr;
}
impl<T: ToExpr> ToExpr for ProjectResult<T> {
fn to_expr(self) -> GenExpr {
match self {
Err(e) => bot_obj(e),
Ok(t) => t.to_expr(),
}
}
}
impl<A: AtomicFeatures> ToExpr for A {
fn to_expr(self) -> GenExpr { atom(self) }
}

View File

@@ -20,7 +20,7 @@ use orchid_base::name::PathSlice;
use orchid_base::reqnot::{ReqNot, Requester}; use orchid_base::reqnot::{ReqNot, Requester};
use crate::atom::AtomInfo; use crate::atom::AtomInfo;
use crate::error::{err_to_api, unpack_err}; use crate::error::{err_or_ref_to_api, unpack_err};
use crate::fs::VirtFS; use crate::fs::VirtFS;
use crate::lexer::LexContext; use crate::lexer::LexContext;
use crate::msg::{recv_parent_msg, send_parent_msg}; use crate::msg::{recv_parent_msg, send_parent_msg};
@@ -155,7 +155,7 @@ pub fn extension_main(data: ExtensionData) {
let data = data.into_api(&*systems_g[&sys].cted.inst()); let data = data.into_api(&*systems_g[&sys].cted.inst());
Ok(Lexed { data, pos: (text.len() - s.len()) as u32 }) Ok(Lexed { data, pos: (text.len() - s.len()) as u32 })
}, },
Err(e) => Err(unpack_err(e).into_iter().map(err_to_api).collect_vec()) Err(e) => Err(unpack_err(e).into_iter().map(err_or_ref_to_api).collect_vec())
})) }))
})); }));
}, },

View File

@@ -42,7 +42,7 @@ pub trait ProjectError: Sized + Send + Sync + 'static {
} }
/// Object-safe version of [ProjectError]. Implement that instead of this. /// Object-safe version of [ProjectError]. Implement that instead of this.
pub trait DynProjectError: Send + Sync { pub trait DynProjectError: Send + Sync + 'static {
/// Access type information about this error /// Access type information about this error
#[must_use] #[must_use]
fn as_any_ref(&self) -> &dyn Any; fn as_any_ref(&self) -> &dyn Any;
@@ -274,23 +274,30 @@ impl ProjectError for MultiError {
} }
} }
pub fn err_to_api(err: ProjectErrorObj) -> ProjErrOrRef { pub fn err_to_api(err: ProjectErrorObj) -> ProjErr {
match err.as_any_ref().downcast_ref() { ProjErr {
Some(RelayedError { id: Some(id), .. }) => ProjErrOrRef::Known(*id),
_ => ProjErrOrRef::New(ProjErr {
description: intern(&*err.description()).marker(), description: intern(&*err.description()).marker(),
message: Arc::new(err.message()), message: Arc::new(err.message()),
locations: err.positions().map(|e| e.to_api()).collect_vec(), locations: err.positions().map(|e| e.to_api()).collect_vec(),
}),
} }
} }
pub fn err_from_api(err: &ProjErrOrRef, reqnot: ReqNot<ExtMsgSet>) -> ProjectErrorObj { pub(crate) fn err_or_ref_to_api(err: ProjectErrorObj) -> ProjErrOrRef {
Arc::new(match err { match err.as_any_ref().downcast_ref() {
ProjErrOrRef::Known(id) => RelayedError { id: Some(*id), reqnot, details: OnceLock::default() }, Some(RelayedError { id: Some(id), .. }) => ProjErrOrRef::Known(*id),
ProjErrOrRef::New(err) => _ => ProjErrOrRef::New(err_to_api(err)),
RelayedError { id: None, reqnot, details: ErrorDetails::from_api(err).into() }, }
}) }
pub fn err_from_api(err: &ProjErr, reqnot: ReqNot<ExtMsgSet>) -> ProjectErrorObj {
Arc::new(RelayedError { id: None, reqnot, details: ErrorDetails::from_api(err).into() })
}
pub(crate) fn err_from_api_or_ref(err: &ProjErrOrRef, reqnot: ReqNot<ExtMsgSet>) -> ProjectErrorObj {
match err {
ProjErrOrRef::Known(id) => Arc::new(RelayedError { id: Some(*id), reqnot, details: OnceLock::default() }),
ProjErrOrRef::New(err) => err_from_api(err, reqnot),
}
} }
struct RelayedError { struct RelayedError {

View File

@@ -1,5 +1,5 @@
use std::ops::Deref; use std::ops::Deref;
use std::sync::OnceLock; use std::sync::{Arc, OnceLock};
use derive_destructure::destructure; use derive_destructure::destructure;
use orchid_api::atom::Atom; use orchid_api::atom::Atom;
@@ -8,7 +8,8 @@ use orchid_base::interner::{deintern, Tok};
use orchid_base::location::Pos; use orchid_base::location::Pos;
use orchid_base::reqnot::Requester; use orchid_base::reqnot::Requester;
use crate::atom::{AtomFactory, ForeignAtom, OwnedAtom, ThinAtom}; use crate::atom::{AtomFactory, AtomicFeatures, ForeignAtom};
use crate::error::{err_from_api, err_to_api, DynProjectError, ProjectErrorObj};
use crate::system::{DynSystem, SysCtx}; use crate::system::{DynSystem, SysCtx};
#[derive(destructure)] #[derive(destructure)]
@@ -22,7 +23,6 @@ impl ExprHandle {
let (tk, ..) = self.destructure(); let (tk, ..) = self.destructure();
tk tk
} }
pub(crate) fn get_tk(&self) -> ExprTicket { self.tk }
pub fn get_ctx(&self) -> SysCtx { self.ctx.clone() } pub fn get_ctx(&self) -> SysCtx { self.ctx.clone() }
} }
impl Clone for ExprHandle { impl Clone for ExprHandle {
@@ -51,9 +51,9 @@ impl OwnedExpr {
}) })
} }
pub fn foreign_atom(self) -> Result<ForeignAtom, Self> { pub fn foreign_atom(self) -> Result<ForeignAtom, Self> {
if let GenExpr { clause: GenClause::Atom(_, atom), position } = self.get_data() { if let GenExpr { clause: GenClause::Atom(_, atom), pos: position } = self.get_data() {
let (atom, position) = (atom.clone(), position.clone()); let (atom, position) = (atom.clone(), position.clone());
return Ok(ForeignAtom { expr: self.handle, atom, position }); return Ok(ForeignAtom { expr: self.handle, atom, pos: position });
} }
Err(self) Err(self)
} }
@@ -65,18 +65,18 @@ impl Deref for OwnedExpr {
#[derive(Clone)] #[derive(Clone)]
pub struct GenExpr { pub struct GenExpr {
pub position: Pos, pub pos: Pos,
pub clause: GenClause, pub clause: GenClause,
} }
impl GenExpr { impl GenExpr {
pub fn to_api(&self, sys: &dyn DynSystem) -> Expr { pub fn to_api(&self, sys: &dyn DynSystem) -> Expr {
Expr { location: self.position.to_api(), clause: self.clause.to_api(sys) } Expr { location: self.pos.to_api(), clause: self.clause.to_api(sys) }
} }
pub fn into_api(self, sys: &dyn DynSystem) -> Expr { pub fn into_api(self, sys: &dyn DynSystem) -> Expr {
Expr { location: self.position.to_api(), clause: self.clause.into_api(sys) } Expr { location: self.pos.to_api(), clause: self.clause.into_api(sys) }
} }
pub fn from_api(api: Expr, ctx: SysCtx) -> Self { pub fn from_api(api: Expr, ctx: SysCtx) -> Self {
Self { position: Pos::from_api(&api.location), clause: GenClause::from_api(api.clause, ctx) } Self { pos: Pos::from_api(&api.location), clause: GenClause::from_api(api.clause, ctx) }
} }
} }
@@ -90,7 +90,7 @@ pub enum GenClause {
Const(Tok<Vec<Tok<String>>>), Const(Tok<Vec<Tok<String>>>),
NewAtom(AtomFactory), NewAtom(AtomFactory),
Atom(ExprTicket, Atom), Atom(ExprTicket, Atom),
Bottom(String), Bottom(ProjectErrorObj),
} }
impl GenClause { impl GenClause {
pub fn to_api(&self, sys: &dyn DynSystem) -> Clause { pub fn to_api(&self, sys: &dyn DynSystem) -> Clause {
@@ -100,7 +100,7 @@ impl GenClause {
Self::Lambda(arg, body) => Clause::Lambda(*arg, Box::new(body.to_api(sys))), Self::Lambda(arg, body) => Clause::Lambda(*arg, Box::new(body.to_api(sys))),
Self::Arg(arg) => Clause::Arg(*arg), Self::Arg(arg) => Clause::Arg(*arg),
Self::Const(name) => Clause::Const(name.marker()), Self::Const(name) => Clause::Const(name.marker()),
Self::Bottom(msg) => Clause::Bottom(msg.clone()), Self::Bottom(msg) => Clause::Bottom(err_to_api(msg.clone())),
Self::NewAtom(fac) => Clause::NewAtom(fac.clone().build(sys)), Self::NewAtom(fac) => Clause::NewAtom(fac.clone().build(sys)),
Self::Atom(tk, atom) => Clause::Atom(*tk, atom.clone()), Self::Atom(tk, atom) => Clause::Atom(*tk, atom.clone()),
Self::Slot(_) => panic!("Slot is forbidden in const tree"), Self::Slot(_) => panic!("Slot is forbidden in const tree"),
@@ -114,7 +114,7 @@ impl GenClause {
Self::Arg(arg) => Clause::Arg(arg), Self::Arg(arg) => Clause::Arg(arg),
Self::Slot(extk) => Clause::Slot(extk.handle.into_tk()), Self::Slot(extk) => Clause::Slot(extk.handle.into_tk()),
Self::Const(name) => Clause::Const(name.marker()), Self::Const(name) => Clause::Const(name.marker()),
Self::Bottom(msg) => Clause::Bottom(msg.clone()), Self::Bottom(msg) => Clause::Bottom(err_to_api(msg)),
Self::NewAtom(fac) => Clause::NewAtom(fac.clone().build(sys)), Self::NewAtom(fac) => Clause::NewAtom(fac.clone().build(sys)),
Self::Atom(tk, atom) => Clause::Atom(tk, atom), Self::Atom(tk, atom) => Clause::Atom(tk, atom),
} }
@@ -124,7 +124,7 @@ impl GenClause {
Clause::Arg(id) => Self::Arg(id), Clause::Arg(id) => Self::Arg(id),
Clause::Lambda(arg, body) => Self::Lambda(arg, Box::new(GenExpr::from_api(*body, ctx))), 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::NewAtom(_) => panic!("Clause::NewAtom should never be received, only sent"),
Clause::Bottom(s) => Self::Bottom(s), Clause::Bottom(s) => Self::Bottom(err_from_api(&s, ctx.reqnot)),
Clause::Call(f, x) => Self::Call( Clause::Call(f, x) => Self::Call(
Box::new(GenExpr::from_api(*f, ctx.clone())), Box::new(GenExpr::from_api(*f, ctx.clone())),
Box::new(GenExpr::from_api(*x, ctx)), Box::new(GenExpr::from_api(*x, ctx)),
@@ -139,11 +139,10 @@ impl GenClause {
} }
} }
} }
fn inherit(clause: GenClause) -> GenExpr { GenExpr { position: Pos::Inherit, clause } } fn inherit(clause: GenClause) -> GenExpr { GenExpr { pos: Pos::Inherit, clause } }
pub fn cnst(path: Tok<Vec<Tok<String>>>) -> GenExpr { inherit(GenClause::Const(path)) } pub fn cnst(path: Tok<Vec<Tok<String>>>) -> GenExpr { inherit(GenClause::Const(path)) }
pub fn val<A: ThinAtom>(atom: A) -> GenExpr { inherit(GenClause::NewAtom(atom.factory())) } pub fn atom<A: AtomicFeatures>(atom: A) -> GenExpr { inherit(GenClause::NewAtom(atom.factory())) }
pub fn obj<A: OwnedAtom>(atom: A) -> GenExpr { inherit(GenClause::NewAtom(atom.factory())) }
pub fn seq(ops: impl IntoIterator<Item = GenExpr>) -> GenExpr { pub fn seq(ops: impl IntoIterator<Item = GenExpr>) -> GenExpr {
fn recur(mut ops: impl Iterator<Item = GenExpr>) -> Option<GenExpr> { fn recur(mut ops: impl Iterator<Item = GenExpr>) -> Option<GenExpr> {
@@ -170,4 +169,5 @@ pub fn call(v: impl IntoIterator<Item = GenExpr>) -> GenExpr {
.expect("Empty call expression") .expect("Empty call expression")
} }
pub fn bot(msg: &str) -> GenClause { GenClause::Bottom(msg.to_string()) } 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)) }

View File

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

View File

@@ -8,7 +8,7 @@ use orchid_base::interner::Tok;
use orchid_base::reqnot::{ReqNot, Requester}; use orchid_base::reqnot::{ReqNot, Requester};
use crate::error::{ use crate::error::{
err_from_api, err_to_api, pack_err, unpack_err, ProjectErrorObj, ProjectResult, err_from_api_or_ref, err_or_ref_to_api, pack_err, unpack_err, ProjectErrorObj, ProjectResult,
}; };
use crate::tree::{GenTok, GenTokTree}; use crate::tree::{GenTok, GenTokTree};
@@ -25,7 +25,7 @@ impl<'a> LexContext<'a> {
self self
.reqnot .reqnot
.request(SubLex { pos: start, id: self.id }) .request(SubLex { pos: start, id: self.id })
.map_err(|e| pack_err(e.iter().map(|e| err_from_api(e, self.reqnot.clone())))) .map_err(|e| pack_err(e.iter().map(|e| err_from_api_or_ref(e, self.reqnot.clone()))))
.map(|lx| (&self.text[lx.pos as usize..], GenTok::Slot(lx.ticket).at(start..lx.pos))) .map(|lx| (&self.text[lx.pos as usize..], GenTok::Slot(lx.ticket).at(start..lx.pos)))
} }
@@ -37,7 +37,7 @@ impl<'a> LexContext<'a> {
pub fn report(&self, e: ProjectErrorObj) { pub fn report(&self, e: ProjectErrorObj) {
for e in unpack_err(e) { for e in unpack_err(e) {
self.reqnot.notify(ReportError(self.sys, err_to_api(e))) self.reqnot.notify(ReportError(self.sys, err_or_ref_to_api(e)))
} }
} }
} }

View File

@@ -10,4 +10,6 @@ pub mod other_system;
pub mod system; pub mod system;
pub mod system_ctor; pub mod system_ctor;
pub mod tree; pub mod tree;
pub mod try_from_expr; pub mod conv;
pub mod atom_thin;
pub mod atom_owned;

View File

@@ -1,9 +1,11 @@
use orchid_api_traits::Decode;
use orchid_api::proto::ExtMsgSet; use orchid_api::proto::ExtMsgSet;
use orchid_api::system::SysId; use orchid_api::system::SysId;
use orchid_base::reqnot::ReqNot; use orchid_base::reqnot::ReqNot;
use typeid::ConstTypeId; use typeid::ConstTypeId;
use crate::atom::{decode_atom, owned_atom_info, AtomCard, AtomInfo, ForeignAtom, TypAtom}; use crate::atom::{get_info, AtomCard, AtomInfo, AtomicFeatures, ForeignAtom, TypAtom};
use crate::fs::DeclFs; use crate::fs::DeclFs;
use crate::fun::Fun; use crate::fun::Fun;
use crate::lexer::LexerObj; use crate::lexer::LexerObj;
@@ -13,42 +15,44 @@ use crate::tree::GenTree;
/// System as consumed by foreign code /// System as consumed by foreign code
pub trait SystemCard: Default + Send + Sync + 'static { pub trait SystemCard: Default + Send + Sync + 'static {
type Ctor: SystemCtor; type Ctor: SystemCtor;
const ATOM_DEFS: &'static [Option<AtomInfo>]; const ATOM_DEFS: &'static [Option<fn() -> &'static AtomInfo>];
} }
pub trait DynSystemCard: Send + Sync + 'static { pub trait DynSystemCard: Send + Sync + 'static {
fn name(&self) -> &'static str; fn name(&self) -> &'static str;
/// Atoms explicitly defined by the system card. Do not rely on this for /// Atoms explicitly defined by the system card. Do not rely on this for
/// querying atoms as it doesn't include the general atom types /// querying atoms as it doesn't include the general atom types
fn atoms(&self) -> &'static [Option<AtomInfo>]; fn atoms(&self) -> &'static [Option<fn() -> &'static AtomInfo>];
} }
/// Atoms supported by this package which may appear in all extensions. /// 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 /// 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) /// marks whether it belongs to this package (0) or the importer (1)
const GENERAL_ATOMS: &[Option<AtomInfo>] = &[Some(owned_atom_info::<Fun>())]; fn general_atoms() -> &'static [Option<fn () -> &'static AtomInfo>] {
&[Some(Fun::info)]
}
pub fn atom_info_for( pub fn atom_info_for(
sys: &(impl DynSystemCard + ?Sized), sys: &(impl DynSystemCard + ?Sized),
tid: ConstTypeId, tid: ConstTypeId,
) -> Option<(u64, &AtomInfo)> { ) -> Option<(u64, &AtomInfo)> {
(sys.atoms().iter().enumerate().map(|(i, o)| (i as u64, o))) (sys.atoms().iter().enumerate().map(|(i, o)| (i as u64, o)))
.chain(GENERAL_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))) .filter_map(|(i, o)| o.as_ref().map(|a| (i, a())))
.find(|ent| ent.1.tid == tid) .find(|ent| ent.1.tid == tid)
} }
pub fn atom_by_idx(sys: &(impl DynSystemCard + ?Sized), tid: u64) -> Option<&AtomInfo> { pub fn atom_by_idx(sys: &(impl DynSystemCard + ?Sized), tid: u64) -> Option<&'static AtomInfo> {
if (tid >> (u64::BITS - 1)) & 1 == 1 { if (tid >> (u64::BITS - 1)) & 1 == 1 {
GENERAL_ATOMS[!tid as usize].as_ref() general_atoms()[!tid as usize].map(|f| f())
} else { } else {
sys.atoms()[tid as usize].as_ref() sys.atoms()[tid as usize].map(|f| f())
} }
} }
impl<T: SystemCard> DynSystemCard for T { impl<T: SystemCard> DynSystemCard for T {
fn name(&self) -> &'static str { T::Ctor::NAME } fn name(&self) -> &'static str { T::Ctor::NAME }
fn atoms(&self) -> &'static [Option<AtomInfo>] { Self::ATOM_DEFS } fn atoms(&self) -> &'static [Option<fn() -> &'static AtomInfo>] { Self::ATOM_DEFS }
} }
/// System as defined by author /// System as defined by author
@@ -73,12 +77,18 @@ impl<T: System> DynSystem for T {
} }
pub fn downcast_atom<A: AtomCard>(foreign: ForeignAtom) -> Result<TypAtom<A>, ForeignAtom> { pub fn downcast_atom<A: AtomCard>(foreign: ForeignAtom) -> Result<TypAtom<A>, ForeignAtom> {
match (foreign.expr.get_ctx().cted.deps()) let mut data = &foreign.atom.data[..];
.find(|s| s.id() == foreign.atom.owner) let ctx = foreign.expr.get_ctx();
.and_then(|sys| decode_atom::<A>(sys.get_card(), &foreign.atom)) 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);
match info_ent {
None => Err(foreign), None => Err(foreign),
Some(value) => Ok(TypAtom { value, data: foreign }), Some((_, info)) => {
let val = (info.decode)(data);
let value = *val.downcast::<A::Data>().expect("atom decode returned wrong type");
Ok(TypAtom { value, data: foreign })
},
} }
} }

View File

@@ -14,6 +14,7 @@ use ordered_float::NotNan;
use trait_set::trait_set; use trait_set::trait_set;
use crate::atom::AtomFactory; use crate::atom::AtomFactory;
use crate::conv::ToExpr;
use crate::expr::GenExpr; use crate::expr::GenExpr;
use crate::system::DynSystem; use crate::system::DynSystem;
@@ -113,7 +114,7 @@ pub struct GenTree {
pub location: Pos, pub location: Pos,
} }
impl GenTree { impl GenTree {
pub fn cnst(gc: GenExpr) -> Self { GenItem::Const(gc).at(Pos::Inherit) } pub fn cnst(gc: impl ToExpr) -> Self { GenItem::Const(gc.to_expr()).at(Pos::Inherit) }
pub fn module<'a>(entries: impl IntoIterator<Item = (&'a str, GenTree)>) -> Self { pub fn module<'a>(entries: impl IntoIterator<Item = (&'a str, GenTree)>) -> Self {
GenItem::Mod(entries.into_iter().map(|(k, v)| (k.to_string(), v)).collect()).at(Pos::Inherit) GenItem::Mod(entries.into_iter().map(|(k, v)| (k.to_string(), v)).collect()).at(Pos::Inherit)
} }

View File

@@ -1,16 +0,0 @@
use crate::error::ProjectResult;
use crate::expr::{ExprHandle, OwnedExpr};
pub trait TryFromExpr: Sized {
fn try_from_expr(expr: ExprHandle) -> ProjectResult<Self>;
}
impl TryFromExpr for OwnedExpr {
fn try_from_expr(expr: ExprHandle) -> ProjectResult<Self> { Ok(OwnedExpr::new(expr)) }
}
impl<T: TryFromExpr, U: TryFromExpr> TryFromExpr for (T, U) {
fn try_from_expr(expr: ExprHandle) -> ProjectResult<Self> {
Ok((T::try_from_expr(expr.clone())?, U::try_from_expr(expr)?))
}
}

View File

@@ -9,7 +9,7 @@ use hashbrown::HashMap;
use itertools::Itertools; use itertools::Itertools;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use orchid_api::atom::{Atom, AtomDrop, AtomSame, CallRef, FinalCall, Fwd, Fwded}; use orchid_api::atom::{Atom, AtomDrop, AtomSame, CallRef, FinalCall, Fwd, Fwded};
use orchid_api::error::{ErrNotif, ProjErr, ProjErrOrRef, ProjResult, ReportError}; use orchid_api::error::{ErrNotif, ProjErrOrRef, ProjResult, ReportError};
use orchid_api::expr::{Acquire, Expr, ExprNotif, ExprTicket, Release, Relocate}; use orchid_api::expr::{Acquire, Expr, ExprNotif, ExprTicket, Release, Relocate};
use orchid_api::interner::IntReq; use orchid_api::interner::IntReq;
use orchid_api::parser::CharFilter; use orchid_api::parser::CharFilter;

View File

@@ -5,6 +5,7 @@ edition = "2021"
[dependencies] [dependencies]
itertools = "0.13.0" itertools = "0.13.0"
once_cell = "1.19.0"
orchid-api = { version = "0.1.0", path = "../orchid-api" } orchid-api = { version = "0.1.0", path = "../orchid-api" }
orchid-api-derive = { version = "0.1.0", path = "../orchid-api-derive" } orchid-api-derive = { version = "0.1.0", path = "../orchid-api-derive" }
orchid-api-traits = { version = "0.1.0", path = "../orchid-api-traits" } orchid-api-traits = { version = "0.1.0", path = "../orchid-api-traits" }

View File

@@ -1,11 +1,15 @@
use orchid_extension::atom::owned_atom_info; use std::sync::Arc;
use orchid_extension::atom::AtomicFeatures;
use orchid_extension::fs::DeclFs; use orchid_extension::fs::DeclFs;
use orchid_extension::fun::Fun;
use orchid_extension::system::{System, SystemCard}; use orchid_extension::system::{System, SystemCard};
use orchid_extension::system_ctor::SystemCtor; use orchid_extension::system_ctor::SystemCtor;
use orchid_extension::tree::GenTree; use orchid_extension::tree::GenTree;
use crate::string::str_atom::StringAtom; use crate::string::str_atom::StringAtom;
use crate::string::str_leer::StringLexer; use crate::string::str_leer::StringLexer;
use crate::OrcString;
#[derive(Default)] #[derive(Default)]
pub struct StdSystem; pub struct StdSystem;
@@ -18,13 +22,16 @@ impl SystemCtor for StdSystem {
} }
impl SystemCard for StdSystem { impl SystemCard for StdSystem {
type Ctor = Self; type Ctor = Self;
const ATOM_DEFS: &'static [Option<orchid_extension::atom::AtomInfo>] = const ATOM_DEFS: &'static [Option<fn() -> &'static orchid_extension::atom::AtomInfo>] = &[
&[Some(owned_atom_info::<StringAtom>())]; Some(StringAtom::info)
];
} }
impl System for StdSystem { impl System for StdSystem {
fn lexers() -> Vec<orchid_extension::lexer::LexerObj> { vec![&StringLexer] } fn lexers() -> Vec<orchid_extension::lexer::LexerObj> { vec![&StringLexer] }
fn vfs() -> DeclFs { DeclFs::Mod(&[]) } fn vfs() -> DeclFs { DeclFs::Mod(&[]) }
fn env() -> GenTree { fn env() -> GenTree {
GenTree::module([("std", GenTree::module([("string", GenTree::module([]))]))]) GenTree::module([("std", GenTree::module([("string", GenTree::module([
("concat", GenTree::cnst(Fun::new(|left: OrcString| Fun::new(move |right: OrcString| StringAtom::new(Arc::new(left.get_string().to_string() + &right.get_string()))))))
]))]))])
} }
} }

View File

@@ -8,11 +8,12 @@ use orchid_api_traits::{Encode, Request};
use orchid_base::id_store::IdStore; use orchid_base::id_store::IdStore;
use orchid_base::interner::{deintern, Tok}; use orchid_base::interner::{deintern, Tok};
use orchid_base::location::Pos; use orchid_base::location::Pos;
use orchid_extension::atom::{AtomCard, OwnedAtom, TypAtom}; use orchid_extension::atom::{Atomic, TypAtom};
use orchid_extension::atom_owned::{OwnedAtom, OwnedVariant};
use orchid_extension::error::{ProjectError, ProjectResult}; use orchid_extension::error::{ProjectError, ProjectResult};
use orchid_extension::expr::{ExprHandle, OwnedExpr}; use orchid_extension::expr::{ExprHandle, OwnedExpr};
use orchid_extension::system::{downcast_atom, SysCtx}; use orchid_extension::system::{downcast_atom, SysCtx};
use orchid_extension::try_from_expr::TryFromExpr; use orchid_extension::conv::TryFromExpr;
pub static STR_REPO: IdStore<Arc<String>> = IdStore::new(); pub static STR_REPO: IdStore<Arc<String>> = IdStore::new();
@@ -31,7 +32,8 @@ pub(crate) enum StringAtom {
Val(NonZeroU64), Val(NonZeroU64),
Int(Tok<String>), Int(Tok<String>),
} }
impl AtomCard for StringAtom { impl Atomic for StringAtom {
type Variant = OwnedVariant;
type Data = StringVal; type Data = StringVal;
type Req = StringGetVal; type Req = StringGetVal;
} }
@@ -72,6 +74,7 @@ impl OwnedAtom for StringAtom {
} }
} }
#[derive(Clone)]
pub struct OrcString(TypAtom<StringAtom>); pub struct OrcString(TypAtom<StringAtom>);
impl OrcString { impl OrcString {
pub fn get_string(&self) -> Arc<String> { pub fn get_string(&self) -> Arc<String> {
@@ -92,9 +95,9 @@ impl ProjectError for NotString {
} }
} }
impl TryFromExpr for OrcString { impl TryFromExpr for OrcString {
fn try_from_expr(expr: ExprHandle) -> ProjectResult<Self> { fn try_from_expr(expr: ExprHandle) -> ProjectResult<OrcString> {
(OwnedExpr::new(expr).foreign_atom().map_err(|expr| expr.position.clone())) (OwnedExpr::new(expr).foreign_atom().map_err(|expr| expr.pos.clone()))
.and_then(|fatom| downcast_atom(fatom).map_err(|f| f.position)) .and_then(|fatom| downcast_atom(fatom).map_err(|f| f.pos))
.map_err(|p| NotString(p).pack()) .map_err(|p| NotString(p).pack())
.map(OrcString) .map(OrcString)
} }

View File

@@ -3,7 +3,7 @@ use orchid_base::interner::intern;
use orchid_base::location::Pos; use orchid_base::location::Pos;
use orchid_base::name::VName; use orchid_base::name::VName;
use orchid_base::vname; use orchid_base::vname;
use orchid_extension::atom::OwnedAtom; use orchid_extension::atom::AtomicFeatures;
use orchid_extension::error::{ErrorSansOrigin, ProjectErrorObj, ProjectResult}; use orchid_extension::error::{ErrorSansOrigin, ProjectErrorObj, ProjectResult};
use orchid_extension::lexer::{LexContext, Lexer}; use orchid_extension::lexer::{LexContext, Lexer};
use orchid_extension::tree::{wrap_tokv, GenTok, GenTokTree}; use orchid_extension::tree::{wrap_tokv, GenTok, GenTokTree};