diff --git a/Cargo.lock b/Cargo.lock index 70572b0..638b5ae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -326,6 +326,7 @@ dependencies = [ "itertools", "konst", "never", + "once_cell", "orchid-api", "orchid-api-derive", "orchid-api-traits", @@ -356,6 +357,7 @@ name = "orchid-std" version = "0.1.0" dependencies = [ "itertools", + "once_cell", "orchid-api", "orchid-api-derive", "orchid-api-traits", diff --git a/notes/crates.md b/notes/crates.md new file mode 100644 index 0000000..eb60a8a --- /dev/null +++ b/notes/crates.md @@ -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. \ No newline at end of file diff --git a/orchid-api-traits/src/hier2.rs b/orchid-api-traits/src/hier2.rs deleted file mode 100644 index 8188100..0000000 --- a/orchid-api-traits/src/hier2.rs +++ /dev/null @@ -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 { - type Parent: TreeRolePicker; -} - -pub trait Inherits {} - -// impl Inherits for T {} -impl Inherits for This where This: Inherits {} diff --git a/orchid-api-traits/src/hierarchy.rs b/orchid-api-traits/src/hierarchy.rs index b749e02..16eccbb 100644 --- a/orchid-api-traits/src/hierarchy.rs +++ b/orchid-api-traits/src/hierarchy.rs @@ -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. /// Implementors are [True] and [False] pub trait TLBool {} @@ -13,17 +8,6 @@ impl TLBool for TLTrue {} pub struct 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 /// on the hierarchy pub trait InHierarchy: Clone { diff --git a/orchid-api-traits/src/lib.rs b/orchid-api-traits/src/lib.rs index be92cf0..8444a33 100644 --- a/orchid-api-traits/src/lib.rs +++ b/orchid-api-traits/src/lib.rs @@ -6,7 +6,6 @@ mod relations; pub use coding::{Coding, Decode, Encode}; pub use helpers::{encode_enum, read_exact, write_exact}; pub use hierarchy::{ - Base, Extends, HierarchyRole, InHierarchy, Subtype, TLBool, TLFalse, TLTrue, UnderRoot, - UnderRootImpl, + Extends, InHierarchy, TLBool, TLFalse, TLTrue, UnderRoot, }; pub use relations::{Channel, MsgSet, Request}; diff --git a/orchid-api/src/expr.rs b/orchid-api/src/expr.rs index b8ab177..4b6e0d9 100644 --- a/orchid-api/src/expr.rs +++ b/orchid-api/src/expr.rs @@ -4,6 +4,7 @@ use orchid_api_derive::{Coding, Hierarchy}; use orchid_api_traits::Request; use crate::atom::{Atom, LocalAtom}; +use crate::error::ProjErr; use crate::interner::TStrv; use crate::location::Location; use crate::proto::{ExtHostNotif, ExtHostReq}; @@ -83,7 +84,7 @@ pub enum Clause { /// A reference to a constant Const(TStrv), /// A static runtime error. - Bottom(String), + Bottom(ProjErr), } #[derive(Clone, Debug, Coding)] diff --git a/orchid-extension/Cargo.toml b/orchid-extension/Cargo.toml index 3e5fb0a..30e3cf3 100644 --- a/orchid-extension/Cargo.toml +++ b/orchid-extension/Cargo.toml @@ -13,6 +13,7 @@ hashbrown = "0.14.5" itertools = "0.13.0" konst = "0.3.9" never = "0.1.0" +once_cell = "1.19.0" orchid-api = { version = "0.1.0", path = "../orchid-api" } orchid-api-derive = { version = "0.1.0", path = "../orchid-api-derive" } orchid-api-traits = { version = "0.1.0", path = "../orchid-api-traits" } diff --git a/orchid-extension/src/atom.rs b/orchid-extension/src/atom.rs index 7a69b33..a7ffca7 100644 --- a/orchid-extension/src/atom.rs +++ b/orchid-extension/src/atom.rs @@ -1,75 +1,60 @@ use std::any::{type_name, Any}; -use std::borrow::Cow; -use std::fmt; use std::io::{Read, Write}; -use std::num::NonZeroU64; use std::ops::Deref; use dyn_clone::{clone_box, DynClone}; use orchid_api::atom::{Atom, Fwd, LocalAtom}; use orchid_api::expr::ExprTicket; -use orchid_api::system::SysId; -use orchid_api_traits::{Coding, Decode, Encode, Request}; -use orchid_base::id_store::{IdRecord, IdStore}; +use orchid_api_traits::{Coding, Decode, Request}; use orchid_base::location::Pos; use orchid_base::reqnot::Requester; use trait_set::trait_set; 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}; pub trait AtomCard: 'static + Sized { - // type Owner: SystemCard; type Data: Clone + Coding + Sized; type Req: Coding; } +pub trait AtomicVariant {} +pub trait Atomic: 'static + Sized { + type Variant: AtomicVariant; + type Data: Clone + Coding + Sized; + type Req: Coding; +} +impl AtomCard for A { + type Data = ::Data; + type Req = ::Req; +} + +pub trait AtomicFeatures: Atomic { + fn factory(self) -> AtomFactory; + fn info() -> &'static AtomInfo; +} +pub trait AtomicFeaturesImpl { + fn _factory(self) -> AtomFactory; + fn _info() -> &'static AtomInfo; +} +impl> AtomicFeatures for A { + fn factory(self) -> AtomFactory { self._factory() } + fn info() -> &'static AtomInfo { Self::_info() } +} + pub fn get_info(sys: &(impl DynSystemCard + ?Sized)) -> (u64, &AtomInfo) { atom_info_for(sys, ConstTypeId::of::()).unwrap_or_else(|| { panic!("Atom {} not associated with system {}", type_name::(), sys.name()) }) } -pub fn encode_atom_nodrop( - sys: &(impl DynSystemCard + ?Sized), - data: &A::Data, -) -> LocalAtom { - let mut buf = get_info::(sys).0.enc_vec(); - data.encode(&mut buf); - LocalAtom { drop: false, data: buf } -} - -pub fn encode_atom_drop( - sys_id: SysId, - sys: &(impl DynSystemCard + ?Sized), - atom_id: u64, - data: &A::Data, -) -> Atom { - let mut buf = get_info::(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( - sys: &(impl DynSystemCard + ?Sized), - Atom { data, drop: _, owner: _ }: &Atom, -) -> Option { - let (info_pos, info) = get_info::(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)] pub struct ForeignAtom { pub expr: ExprHandle, pub atom: Atom, - pub position: Pos, + pub pos: Pos, } impl ForeignAtom {} @@ -93,126 +78,13 @@ impl Deref for TypAtom { pub struct AtomInfo { pub tid: ConstTypeId, pub decode: fn(&[u8]) -> Box, - pub call: fn(&[u8], SysCtx, ExprTicket) -> GenClause, - pub call_ref: fn(&[u8], SysCtx, ExprTicket) -> GenClause, + pub call: fn(&[u8], SysCtx, ExprTicket) -> GenExpr, + pub call_ref: fn(&[u8], SysCtx, ExprTicket) -> GenExpr, pub same: fn(&[u8], SysCtx, &[u8]) -> bool, pub handle_req: fn(&[u8], SysCtx, &mut dyn Read, &mut dyn Write), pub drop: fn(&[u8], SysCtx), } -pub trait ThinAtom: AtomCard + 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::() - ); - 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::(sys.dyn_card(), &self)) - } -} - -pub const fn thin_atom_info() -> AtomInfo { - AtomInfo { - tid: ConstTypeId::of::(), - 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::() - ); - 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, 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, ctx: SysCtx); -} -impl DynOwnedAtom for T { - fn atom_tid(&self) -> ConstTypeId { ConstTypeId::of::() } - 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, 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::() != 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, ::Req::decode(req), rep) - } - fn dyn_free(self: Box, ctx: SysCtx) { self.free(ctx) } -} - -pub(crate) static OBJ_STORE: IdStore> = IdStore::new(); - -pub const fn owned_atom_info() -> AtomInfo { - fn with_atom(mut b: &[u8], f: impl FnOnce(IdRecord<'_, Box>) -> U) -> U { - f(OBJ_STORE.get(NonZeroU64::decode(&mut b)).expect("Received invalid atom ID")) - } - AtomInfo { - tid: ConstTypeId::of::(), - 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! { pub trait AtomFactoryFn = FnOnce(&dyn DynSystem) -> LocalAtom + DynClone; } @@ -226,3 +98,8 @@ impl AtomFactory { impl Clone for AtomFactory { 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"; +} \ No newline at end of file diff --git a/orchid-extension/src/atom_owned.rs b/orchid-extension/src/atom_owned.rs new file mode 100644 index 0000000..a8a90cb --- /dev/null +++ b/orchid-extension/src/atom_owned.rs @@ -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> AtomicFeaturesImpl 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(mut b: &[u8], f: impl FnOnce(IdRecord<'_, Box>) -> U) -> U { + f(OBJ_STORE.get(NonZeroU64::decode(&mut b)).expect("Received invalid atom ID")) + } + &const { + AtomInfo { + tid: ConstTypeId::of::(), + decode: |mut b| Box::new(::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::() + ); + 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, 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, ctx: SysCtx); +} +impl DynOwnedAtom for T { + fn atom_tid(&self) -> ConstTypeId { ConstTypeId::of::() } + 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, 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::() != 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, ::Req::decode(req), rep) + } + fn dyn_free(self: Box, ctx: SysCtx) { self.free(ctx) } +} + +pub(crate) static OBJ_STORE: IdStore> = IdStore::new(); \ No newline at end of file diff --git a/orchid-extension/src/atom_thin.rs b/orchid-extension/src/atom_thin.rs new file mode 100644 index 0000000..4f6a109 --- /dev/null +++ b/orchid-extension/src/atom_thin.rs @@ -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> AtomicFeaturesImpl for A { + fn _factory(self) -> AtomFactory { + AtomFactory::new(move |sys| { + let mut buf = get_info::(sys.dyn_card()).0.enc_vec(); + self.encode(&mut buf); + LocalAtom { drop: false, data: buf } + }) + } + fn _info() -> &'static AtomInfo { + &const { + AtomInfo { + tid: ConstTypeId::of::(), + 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 + 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::() + ); + false + } + fn handle_req(&self, ctx: SysCtx, req: Self::Req, rep: &mut (impl Write + ?Sized)); +} diff --git a/orchid-extension/src/conv.rs b/orchid-extension/src/conv.rs new file mode 100644 index 0000000..ef77360 --- /dev/null +++ b/orchid-extension/src/conv.rs @@ -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; +} + +impl TryFromExpr for OwnedExpr { + fn try_from_expr(expr: ExprHandle) -> ProjectResult { Ok(OwnedExpr::new(expr)) } +} + +impl TryFromExpr for (T, U) { + fn try_from_expr(expr: ExprHandle) -> ProjectResult { + 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 TryFromExpr for TypAtom { + fn try_from_expr(expr: ExprHandle) -> ProjectResult { + 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 ToExpr for ProjectResult { + fn to_expr(self) -> GenExpr { + match self { + Err(e) => bot_obj(e), + Ok(t) => t.to_expr(), + } + } +} + +impl ToExpr for A { + fn to_expr(self) -> GenExpr { atom(self) } +} \ No newline at end of file diff --git a/orchid-extension/src/entrypoint.rs b/orchid-extension/src/entrypoint.rs index cd23138..3317b82 100644 --- a/orchid-extension/src/entrypoint.rs +++ b/orchid-extension/src/entrypoint.rs @@ -20,7 +20,7 @@ use orchid_base::name::PathSlice; use orchid_base::reqnot::{ReqNot, Requester}; 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::lexer::LexContext; 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()); 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()) })) })); }, diff --git a/orchid-extension/src/error.rs b/orchid-extension/src/error.rs index 1778b3a..1df7a88 100644 --- a/orchid-extension/src/error.rs +++ b/orchid-extension/src/error.rs @@ -42,7 +42,7 @@ pub trait ProjectError: Sized + Send + Sync + 'static { } /// 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 #[must_use] fn as_any_ref(&self) -> &dyn Any; @@ -274,23 +274,30 @@ impl ProjectError for MultiError { } } -pub fn err_to_api(err: ProjectErrorObj) -> ProjErrOrRef { - match err.as_any_ref().downcast_ref() { - Some(RelayedError { id: Some(id), .. }) => ProjErrOrRef::Known(*id), - _ => ProjErrOrRef::New(ProjErr { - description: intern(&*err.description()).marker(), - message: Arc::new(err.message()), - locations: err.positions().map(|e| e.to_api()).collect_vec(), - }), +pub fn err_to_api(err: ProjectErrorObj) -> ProjErr { + ProjErr { + description: intern(&*err.description()).marker(), + message: Arc::new(err.message()), + locations: err.positions().map(|e| e.to_api()).collect_vec(), } } -pub fn err_from_api(err: &ProjErrOrRef, reqnot: ReqNot) -> ProjectErrorObj { - Arc::new(match err { - ProjErrOrRef::Known(id) => RelayedError { id: Some(*id), reqnot, details: OnceLock::default() }, - ProjErrOrRef::New(err) => - RelayedError { id: None, reqnot, details: ErrorDetails::from_api(err).into() }, - }) +pub(crate) fn err_or_ref_to_api(err: ProjectErrorObj) -> ProjErrOrRef { + match err.as_any_ref().downcast_ref() { + Some(RelayedError { id: Some(id), .. }) => ProjErrOrRef::Known(*id), + _ => ProjErrOrRef::New(err_to_api(err)), + } +} + +pub fn err_from_api(err: &ProjErr, reqnot: ReqNot) -> 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) -> 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 { diff --git a/orchid-extension/src/expr.rs b/orchid-extension/src/expr.rs index f957328..b80174b 100644 --- a/orchid-extension/src/expr.rs +++ b/orchid-extension/src/expr.rs @@ -1,5 +1,5 @@ use std::ops::Deref; -use std::sync::OnceLock; +use std::sync::{Arc, OnceLock}; use derive_destructure::destructure; use orchid_api::atom::Atom; @@ -8,7 +8,8 @@ use orchid_base::interner::{deintern, Tok}; use orchid_base::location::Pos; 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}; #[derive(destructure)] @@ -22,7 +23,6 @@ impl ExprHandle { let (tk, ..) = self.destructure(); tk } - pub(crate) fn get_tk(&self) -> ExprTicket { self.tk } pub fn get_ctx(&self) -> SysCtx { self.ctx.clone() } } impl Clone for ExprHandle { @@ -51,9 +51,9 @@ impl OwnedExpr { }) } pub fn foreign_atom(self) -> Result { - 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()); - return Ok(ForeignAtom { expr: self.handle, atom, position }); + return Ok(ForeignAtom { expr: self.handle, atom, pos: position }); } Err(self) } @@ -65,18 +65,18 @@ impl Deref for OwnedExpr { #[derive(Clone)] pub struct GenExpr { - pub position: Pos, + pub pos: Pos, pub clause: GenClause, } impl GenExpr { 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 { - 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 { - 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>>), NewAtom(AtomFactory), Atom(ExprTicket, Atom), - Bottom(String), + Bottom(ProjectErrorObj), } impl GenClause { 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::Arg(arg) => Clause::Arg(*arg), 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::Atom(tk, atom) => Clause::Atom(*tk, atom.clone()), Self::Slot(_) => panic!("Slot is forbidden in const tree"), @@ -114,7 +114,7 @@ impl GenClause { Self::Arg(arg) => Clause::Arg(arg), Self::Slot(extk) => Clause::Slot(extk.handle.into_tk()), 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::Atom(tk, atom) => Clause::Atom(tk, atom), } @@ -124,7 +124,7 @@ impl GenClause { 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(s), + Clause::Bottom(s) => Self::Bottom(err_from_api(&s, ctx.reqnot)), Clause::Call(f, x) => Self::Call( Box::new(GenExpr::from_api(*f, ctx.clone())), 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>>) -> GenExpr { inherit(GenClause::Const(path)) } -pub fn val(atom: A) -> GenExpr { inherit(GenClause::NewAtom(atom.factory())) } -pub fn obj(atom: A) -> GenExpr { inherit(GenClause::NewAtom(atom.factory())) } +pub fn atom(atom: A) -> GenExpr { inherit(GenClause::NewAtom(atom.factory())) } pub fn seq(ops: impl IntoIterator) -> GenExpr { fn recur(mut ops: impl Iterator) -> Option { @@ -170,4 +169,5 @@ pub fn call(v: impl IntoIterator) -> GenExpr { .expect("Empty call expression") } -pub fn bot(msg: &str) -> GenClause { GenClause::Bottom(msg.to_string()) } +pub fn bot(msg: E) -> GenExpr { inherit(GenClause::Bottom(Arc::new(msg))) } +pub fn bot_obj(e: ProjectErrorObj) -> GenExpr { inherit(GenClause::Bottom(e)) } diff --git a/orchid-extension/src/fun.rs b/orchid-extension/src/fun.rs index 956ec69..b64106c 100644 --- a/orchid-extension/src/fun.rs +++ b/orchid-extension/src/fun.rs @@ -4,31 +4,34 @@ use dyn_clone::{clone_box, DynClone}; use never::Never; use trait_set::trait_set; -use crate::atom::{AtomCard, OwnedAtom}; -use crate::expr::{ExprHandle, GenClause}; +use crate::atom::Atomic; +use crate::atom_owned::{OwnedAtom, OwnedVariant}; +use crate::expr::{ExprHandle, GenExpr}; use crate::system::SysCtx; +use crate::conv::{ToExpr, TryFromExpr}; trait_set! { - trait FunCB = FnOnce(ExprHandle) -> GenClause + DynClone + Send + Sync + 'static; + trait FunCB = FnOnce(ExprHandle) -> GenExpr + DynClone + Send + Sync + 'static; } pub struct Fun(Box); impl Fun { - pub fn new(f: impl FnOnce(ExprHandle) -> GenClause + Clone + Send + Sync + 'static) -> Self { - Self(Box::new(f)) + pub fn new(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 AtomCard for Fun { +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) -> GenClause { self.clone().call(arg) } - fn call(self, arg: ExprHandle) -> GenClause { (self.0)(arg) } + 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, req: Self::Req, _rep: &mut (impl std::io::Write + ?Sized)) { match req {} } diff --git a/orchid-extension/src/lexer.rs b/orchid-extension/src/lexer.rs index 6637522..91f8a4e 100644 --- a/orchid-extension/src/lexer.rs +++ b/orchid-extension/src/lexer.rs @@ -8,7 +8,7 @@ use orchid_base::interner::Tok; use orchid_base::reqnot::{ReqNot, Requester}; 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}; @@ -25,7 +25,7 @@ impl<'a> LexContext<'a> { self .reqnot .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))) } @@ -37,7 +37,7 @@ impl<'a> LexContext<'a> { pub fn report(&self, e: ProjectErrorObj) { 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))) } } } diff --git a/orchid-extension/src/lib.rs b/orchid-extension/src/lib.rs index 9d6acf3..e2e23bf 100644 --- a/orchid-extension/src/lib.rs +++ b/orchid-extension/src/lib.rs @@ -10,4 +10,6 @@ pub mod other_system; pub mod system; pub mod system_ctor; pub mod tree; -pub mod try_from_expr; +pub mod conv; +pub mod atom_thin; +pub mod atom_owned; diff --git a/orchid-extension/src/system.rs b/orchid-extension/src/system.rs index 4096edd..0312259 100644 --- a/orchid-extension/src/system.rs +++ b/orchid-extension/src/system.rs @@ -1,9 +1,11 @@ +use orchid_api_traits::Decode; + use orchid_api::proto::ExtMsgSet; use orchid_api::system::SysId; use orchid_base::reqnot::ReqNot; 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::fun::Fun; use crate::lexer::LexerObj; @@ -13,42 +15,44 @@ use crate::tree::GenTree; /// System as consumed by foreign code pub trait SystemCard: Default + Send + Sync + 'static { type Ctor: SystemCtor; - const ATOM_DEFS: &'static [Option]; + const ATOM_DEFS: &'static [Option &'static AtomInfo>]; } pub trait DynSystemCard: Send + Sync + 'static { fn name(&self) -> &'static str; /// Atoms explicitly defined by the system card. Do not rely on this for /// querying atoms as it doesn't include the general atom types - fn atoms(&self) -> &'static [Option]; + fn atoms(&self) -> &'static [Option &'static AtomInfo>]; } /// 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) -const GENERAL_ATOMS: &[Option] = &[Some(owned_atom_info::())]; +fn general_atoms() -> &'static [Option &'static AtomInfo>] { + &[Some(Fun::info)] +} pub fn atom_info_for( sys: &(impl DynSystemCard + ?Sized), tid: ConstTypeId, ) -> Option<(u64, &AtomInfo)> { (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))) + .chain(general_atoms().iter().enumerate().map(|(i, o)| (!(i as u64), o))) + .filter_map(|(i, o)| o.as_ref().map(|a| (i, a()))) .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 { - GENERAL_ATOMS[!tid as usize].as_ref() + general_atoms()[!tid as usize].map(|f| f()) } else { - sys.atoms()[tid as usize].as_ref() + sys.atoms()[tid as usize].map(|f| f()) } } impl DynSystemCard for T { fn name(&self) -> &'static str { T::Ctor::NAME } - fn atoms(&self) -> &'static [Option] { Self::ATOM_DEFS } + fn atoms(&self) -> &'static [Option &'static AtomInfo>] { Self::ATOM_DEFS } } /// System as defined by author @@ -73,12 +77,18 @@ impl DynSystem for T { } pub fn downcast_atom(foreign: ForeignAtom) -> Result, ForeignAtom> { - match (foreign.expr.get_ctx().cted.deps()) - .find(|s| s.id() == foreign.atom.owner) - .and_then(|sys| decode_atom::(sys.get_card(), &foreign.atom)) - { + let mut data = &foreign.atom.data[..]; + let ctx = foreign.expr.get_ctx(); + let info_ent = (ctx.cted.deps().find(|s| s.id() == foreign.atom.owner)) + .map(|sys| get_info::(sys.get_card())) + .filter(|(pos, _)| u64::decode(&mut data) == *pos); + match info_ent { None => Err(foreign), - Some(value) => Ok(TypAtom { value, data: foreign }), + Some((_, info)) => { + let val = (info.decode)(data); + let value = *val.downcast::().expect("atom decode returned wrong type"); + Ok(TypAtom { value, data: foreign }) + }, } } diff --git a/orchid-extension/src/tree.rs b/orchid-extension/src/tree.rs index b511f0a..4afa4ea 100644 --- a/orchid-extension/src/tree.rs +++ b/orchid-extension/src/tree.rs @@ -14,6 +14,7 @@ use ordered_float::NotNan; use trait_set::trait_set; use crate::atom::AtomFactory; +use crate::conv::ToExpr; use crate::expr::GenExpr; use crate::system::DynSystem; @@ -113,7 +114,7 @@ pub struct GenTree { pub location: Pos, } 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) -> Self { GenItem::Mod(entries.into_iter().map(|(k, v)| (k.to_string(), v)).collect()).at(Pos::Inherit) } diff --git a/orchid-extension/src/try_from_expr.rs b/orchid-extension/src/try_from_expr.rs deleted file mode 100644 index bdb4bf6..0000000 --- a/orchid-extension/src/try_from_expr.rs +++ /dev/null @@ -1,16 +0,0 @@ -use crate::error::ProjectResult; -use crate::expr::{ExprHandle, OwnedExpr}; - -pub trait TryFromExpr: Sized { - fn try_from_expr(expr: ExprHandle) -> ProjectResult; -} - -impl TryFromExpr for OwnedExpr { - fn try_from_expr(expr: ExprHandle) -> ProjectResult { Ok(OwnedExpr::new(expr)) } -} - -impl TryFromExpr for (T, U) { - fn try_from_expr(expr: ExprHandle) -> ProjectResult { - Ok((T::try_from_expr(expr.clone())?, U::try_from_expr(expr)?)) - } -} diff --git a/orchid-host/src/extension.rs b/orchid-host/src/extension.rs index 1b24f5f..ccd68a4 100644 --- a/orchid-host/src/extension.rs +++ b/orchid-host/src/extension.rs @@ -9,7 +9,7 @@ use hashbrown::HashMap; use itertools::Itertools; use lazy_static::lazy_static; 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::interner::IntReq; use orchid_api::parser::CharFilter; diff --git a/orchid-std/Cargo.toml b/orchid-std/Cargo.toml index a88f8c1..f70666b 100644 --- a/orchid-std/Cargo.toml +++ b/orchid-std/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" [dependencies] itertools = "0.13.0" +once_cell = "1.19.0" orchid-api = { version = "0.1.0", path = "../orchid-api" } orchid-api-derive = { version = "0.1.0", path = "../orchid-api-derive" } orchid-api-traits = { version = "0.1.0", path = "../orchid-api-traits" } diff --git a/orchid-std/src/std.rs b/orchid-std/src/std.rs index 19d27b4..4ac65b1 100644 --- a/orchid-std/src/std.rs +++ b/orchid-std/src/std.rs @@ -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::fun::Fun; use orchid_extension::system::{System, SystemCard}; use orchid_extension::system_ctor::SystemCtor; use orchid_extension::tree::GenTree; use crate::string::str_atom::StringAtom; use crate::string::str_leer::StringLexer; +use crate::OrcString; #[derive(Default)] pub struct StdSystem; @@ -18,13 +22,16 @@ impl SystemCtor for StdSystem { } impl SystemCard for StdSystem { type Ctor = Self; - const ATOM_DEFS: &'static [Option] = - &[Some(owned_atom_info::())]; + const ATOM_DEFS: &'static [Option &'static orchid_extension::atom::AtomInfo>] = &[ + Some(StringAtom::info) + ]; } impl System for StdSystem { fn lexers() -> Vec { vec![&StringLexer] } fn vfs() -> DeclFs { DeclFs::Mod(&[]) } 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())))))) + ]))]))]) } } diff --git a/orchid-std/src/string/str_atom.rs b/orchid-std/src/string/str_atom.rs index 7e7ab9b..26d17ac 100644 --- a/orchid-std/src/string/str_atom.rs +++ b/orchid-std/src/string/str_atom.rs @@ -8,11 +8,12 @@ use orchid_api_traits::{Encode, Request}; use orchid_base::id_store::IdStore; use orchid_base::interner::{deintern, Tok}; 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::expr::{ExprHandle, OwnedExpr}; use orchid_extension::system::{downcast_atom, SysCtx}; -use orchid_extension::try_from_expr::TryFromExpr; +use orchid_extension::conv::TryFromExpr; pub static STR_REPO: IdStore> = IdStore::new(); @@ -31,7 +32,8 @@ pub(crate) enum StringAtom { Val(NonZeroU64), Int(Tok), } -impl AtomCard for StringAtom { +impl Atomic for StringAtom { + type Variant = OwnedVariant; type Data = StringVal; type Req = StringGetVal; } @@ -72,6 +74,7 @@ impl OwnedAtom for StringAtom { } } +#[derive(Clone)] pub struct OrcString(TypAtom); impl OrcString { pub fn get_string(&self) -> Arc { @@ -92,9 +95,9 @@ impl ProjectError for NotString { } } impl TryFromExpr for OrcString { - fn try_from_expr(expr: ExprHandle) -> ProjectResult { - (OwnedExpr::new(expr).foreign_atom().map_err(|expr| expr.position.clone())) - .and_then(|fatom| downcast_atom(fatom).map_err(|f| f.position)) + fn try_from_expr(expr: ExprHandle) -> ProjectResult { + (OwnedExpr::new(expr).foreign_atom().map_err(|expr| expr.pos.clone())) + .and_then(|fatom| downcast_atom(fatom).map_err(|f| f.pos)) .map_err(|p| NotString(p).pack()) .map(OrcString) } diff --git a/orchid-std/src/string/str_leer.rs b/orchid-std/src/string/str_leer.rs index b46a5c3..b6e7e8f 100644 --- a/orchid-std/src/string/str_leer.rs +++ b/orchid-std/src/string/str_leer.rs @@ -3,7 +3,7 @@ use orchid_base::interner::intern; use orchid_base::location::Pos; use orchid_base::name::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::lexer::{LexContext, Lexer}; use orchid_extension::tree::{wrap_tokv, GenTok, GenTokTree};