forked from Orchid/orchid
Protocols and operators mostly
This commit is contained in:
@@ -22,7 +22,7 @@ Namespaces are inspired by Rust modules and ES6. Every file and directory is imp
|
|||||||
The project uses both the stable and nightly rust toolchain. Run the examples with
|
The project uses both the stable and nightly rust toolchain. Run the examples with
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
cargo orcx -- exec --proj ./examples/hello-world "src::main::main"
|
cargo orcx --release exec --proj ./examples/hello-world "src::main::main"
|
||||||
```
|
```
|
||||||
|
|
||||||
you can try modifying the examples, but error reporting for the time being is pretty terrible.
|
you can try modifying the examples, but error reporting for the time being is pretty terrible.
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
let my_tuple = option::some t[1, 2]
|
let user = "lorinc" + " " + "bethlenfalvy"
|
||||||
|
let number = 1 + 2
|
||||||
|
let interpolated = "Hello $user $number"
|
||||||
|
|
||||||
let main = match my_tuple {
|
let user =
|
||||||
option::some t[ref head, ..] => head;
|
|
||||||
option::none => "foo";
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ use std::rc::Rc;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::task::{Context, Poll, Wake, Waker};
|
use std::task::{Context, Poll, Wake, Waker};
|
||||||
|
use std::thread::panicking;
|
||||||
|
|
||||||
use futures::Stream;
|
use futures::Stream;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
@@ -155,3 +156,15 @@ pub fn spin_on<Fut: Future>(f: Fut) -> Fut::Output {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create an object that will panic if dropped. [PanicOnDrop::defuse] must be
|
||||||
|
/// called once the particular constraint preventing a drop has passed
|
||||||
|
pub fn assert_no_drop(msg: &'static str) -> PanicOnDrop { PanicOnDrop(true, msg) }
|
||||||
|
|
||||||
|
pub struct PanicOnDrop(bool, &'static str);
|
||||||
|
impl PanicOnDrop {
|
||||||
|
pub fn defuse(mut self) { self.0 = false; }
|
||||||
|
}
|
||||||
|
impl Drop for PanicOnDrop {
|
||||||
|
fn drop(&mut self) { assert!(panicking() || !self.0, "{}", self.1) }
|
||||||
|
}
|
||||||
|
|||||||
@@ -202,6 +202,11 @@ impl Sym {
|
|||||||
pub async fn parse(s: &str) -> Result<Self, EmptyNameError> {
|
pub async fn parse(s: &str) -> Result<Self, EmptyNameError> {
|
||||||
Ok(Sym(iv(&VName::parse(s).await?.into_vec()).await))
|
Ok(Sym(iv(&VName::parse(s).await?.into_vec()).await))
|
||||||
}
|
}
|
||||||
|
/// Read a `::` separated namespaced name from a static string where.
|
||||||
|
pub async fn literal(s: &'static str) -> Self {
|
||||||
|
assert!(!s.is_empty(), "Literal cannot be empty");
|
||||||
|
Self::parse(s).await.unwrap()
|
||||||
|
}
|
||||||
/// Assert that a token isn't empty, and wrap it in a [Sym]
|
/// Assert that a token isn't empty, and wrap it in a [Sym]
|
||||||
pub fn from_tok(t: IStrv) -> Result<Self, EmptyNameError> {
|
pub fn from_tok(t: IStrv) -> Result<Self, EmptyNameError> {
|
||||||
if t.is_empty() { Err(EmptyNameError) } else { Ok(Self(t)) }
|
if t.is_empty() { Err(EmptyNameError) } else { Ok(Self(t)) }
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ use futures::{
|
|||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use orchid_api_traits::{Decode, Encode, Request, UnderRoot};
|
use orchid_api_traits::{Decode, Encode, Request, UnderRoot};
|
||||||
|
|
||||||
|
use crate::future_debug::{PanicOnDrop, assert_no_drop};
|
||||||
use crate::localset::LocalSet;
|
use crate::localset::LocalSet;
|
||||||
|
|
||||||
#[must_use = "Receipts indicate that a required action has been performed within a function. \
|
#[must_use = "Receipts indicate that a required action has been performed within a function. \
|
||||||
@@ -238,9 +239,12 @@ impl IoClient {
|
|||||||
impl Client for IoClient {
|
impl Client for IoClient {
|
||||||
fn start_notif(&self) -> LocalBoxFuture<'_, io::Result<Box<dyn MsgWriter<'_> + '_>>> {
|
fn start_notif(&self) -> LocalBoxFuture<'_, io::Result<Box<dyn MsgWriter<'_> + '_>>> {
|
||||||
Box::pin(async {
|
Box::pin(async {
|
||||||
|
let drop_g = assert_no_drop("Notif future dropped");
|
||||||
let mut o = self.lock_out().await;
|
let mut o = self.lock_out().await;
|
||||||
0u64.encode(o.as_mut()).await?;
|
0u64.encode(o.as_mut()).await?;
|
||||||
Ok(Box::new(IoNotifWriter { o }) as Box<dyn MsgWriter>)
|
drop_g.defuse();
|
||||||
|
Ok(Box::new(IoNotifWriter { o, drop_g: assert_no_drop("Notif writer dropped") })
|
||||||
|
as Box<dyn MsgWriter>)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
fn start_request(&self) -> LocalBoxFuture<'_, io::Result<Box<dyn ReqWriter<'_> + '_>>> {
|
fn start_request(&self) -> LocalBoxFuture<'_, io::Result<Box<dyn ReqWriter<'_> + '_>>> {
|
||||||
@@ -252,11 +256,17 @@ impl Client for IoClient {
|
|||||||
};
|
};
|
||||||
let (cb, reply) = oneshot::channel();
|
let (cb, reply) = oneshot::channel();
|
||||||
let (ack, got_ack) = oneshot::channel();
|
let (ack, got_ack) = oneshot::channel();
|
||||||
|
let drop_g = assert_no_drop("Request future dropped");
|
||||||
self.subscribe.as_ref().clone().send(ReplySub { id, ack, cb }).await.unwrap();
|
self.subscribe.as_ref().clone().send(ReplySub { id, ack, cb }).await.unwrap();
|
||||||
got_ack.await.unwrap();
|
got_ack.await.unwrap();
|
||||||
let mut w = self.lock_out().await;
|
let mut w = self.lock_out().await;
|
||||||
id.encode(w.as_mut()).await?;
|
id.encode(w.as_mut()).await?;
|
||||||
Ok(Box::new(IoReqWriter { reply, w }) as Box<dyn ReqWriter>)
|
drop_g.defuse();
|
||||||
|
Ok(Box::new(IoReqWriter {
|
||||||
|
reply,
|
||||||
|
w,
|
||||||
|
drop_g: assert_no_drop("Request reader dropped without reply"),
|
||||||
|
}) as Box<dyn ReqWriter>)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -264,36 +274,49 @@ impl Client for IoClient {
|
|||||||
struct IoReqWriter {
|
struct IoReqWriter {
|
||||||
reply: oneshot::Receiver<IoGuard<dyn AsyncRead>>,
|
reply: oneshot::Receiver<IoGuard<dyn AsyncRead>>,
|
||||||
w: IoGuard<dyn AsyncWrite>,
|
w: IoGuard<dyn AsyncWrite>,
|
||||||
|
drop_g: PanicOnDrop,
|
||||||
}
|
}
|
||||||
impl<'a> ReqWriter<'a> for IoReqWriter {
|
impl<'a> ReqWriter<'a> for IoReqWriter {
|
||||||
fn writer(&mut self) -> Pin<&mut dyn AsyncWrite> { self.w.as_mut() }
|
fn writer(&mut self) -> Pin<&mut dyn AsyncWrite> { self.w.as_mut() }
|
||||||
fn send(self: Box<Self>) -> LocalBoxFuture<'a, io::Result<Box<dyn RepReader<'a> + 'a>>> {
|
fn send(self: Box<Self>) -> LocalBoxFuture<'a, io::Result<Box<dyn RepReader<'a> + 'a>>> {
|
||||||
Box::pin(async {
|
Box::pin(async {
|
||||||
let Self { reply, mut w } = *self;
|
let Self { reply, mut w, drop_g } = *self;
|
||||||
w.flush().await?;
|
w.flush().await?;
|
||||||
mem::drop(w);
|
mem::drop(w);
|
||||||
let i = reply.await.expect("Client dropped before reply received");
|
let i = reply.await.expect("Client dropped before reply received");
|
||||||
Ok(Box::new(IoRepReader { i }) as Box<dyn RepReader>)
|
drop_g.defuse();
|
||||||
|
Ok(Box::new(IoRepReader {
|
||||||
|
i,
|
||||||
|
drop_g: assert_no_drop("Reply reader dropped without finishing"),
|
||||||
|
}) as Box<dyn RepReader>)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct IoRepReader {
|
struct IoRepReader {
|
||||||
i: IoGuard<dyn AsyncRead>,
|
i: IoGuard<dyn AsyncRead>,
|
||||||
|
drop_g: PanicOnDrop,
|
||||||
}
|
}
|
||||||
impl<'a> RepReader<'a> for IoRepReader {
|
impl<'a> RepReader<'a> for IoRepReader {
|
||||||
fn reader(&mut self) -> Pin<&mut dyn AsyncRead> { self.i.as_mut() }
|
fn reader(&mut self) -> Pin<&mut dyn AsyncRead> { self.i.as_mut() }
|
||||||
fn finish(self: Box<Self>) -> LocalBoxFuture<'static, ()> { Box::pin(async {}) }
|
fn finish(self: Box<Self>) -> LocalBoxFuture<'static, ()> {
|
||||||
|
Box::pin(async { self.drop_g.defuse() })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(destructure)]
|
#[derive(destructure)]
|
||||||
struct IoNotifWriter {
|
struct IoNotifWriter {
|
||||||
o: IoGuard<dyn AsyncWrite>,
|
o: IoGuard<dyn AsyncWrite>,
|
||||||
|
drop_g: PanicOnDrop,
|
||||||
}
|
}
|
||||||
impl<'a> MsgWriter<'a> for IoNotifWriter {
|
impl<'a> MsgWriter<'a> for IoNotifWriter {
|
||||||
fn writer(&mut self) -> Pin<&mut dyn AsyncWrite> { self.o.as_mut() }
|
fn writer(&mut self) -> Pin<&mut dyn AsyncWrite> { self.o.as_mut() }
|
||||||
fn finish(mut self: Box<Self>) -> LocalBoxFuture<'static, io::Result<()>> {
|
fn finish(mut self: Box<Self>) -> LocalBoxFuture<'static, io::Result<()>> {
|
||||||
Box::pin(async move { self.o.flush().await })
|
Box::pin(async move {
|
||||||
|
self.o.flush().await?;
|
||||||
|
self.drop_g.defuse();
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -375,7 +398,8 @@ impl IoCommServer {
|
|||||||
Ok(Event::Exit) => break,
|
Ok(Event::Exit) => break,
|
||||||
Ok(Event::Sub(ReplySub { id, ack, cb })) => {
|
Ok(Event::Sub(ReplySub { id, ack, cb })) => {
|
||||||
pending_replies.insert(id, cb);
|
pending_replies.insert(id, cb);
|
||||||
ack.send(()).unwrap();
|
// this is detected and logged on client
|
||||||
|
let _ = ack.send(());
|
||||||
},
|
},
|
||||||
Ok(Event::Input(0, read)) => {
|
Ok(Event::Input(0, read)) => {
|
||||||
let notif = ¬if;
|
let notif = ¬if;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use std::any::{Any, TypeId, type_name};
|
use std::any::{Any, TypeId, type_name};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt;
|
use std::fmt::{self, Debug};
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::num::NonZeroU32;
|
use std::num::NonZeroU32;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
@@ -144,6 +144,15 @@ impl NotTypAtom {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl Debug for NotTypAtom {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("NotTypAtom")
|
||||||
|
.field("pos", &self.pos)
|
||||||
|
.field("expr", &self.expr)
|
||||||
|
.field("typ.name", &self.typ.name())
|
||||||
|
.finish_non_exhaustive()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait AtomMethod: Request + Coding {
|
pub trait AtomMethod: Request + Coding {
|
||||||
const NAME: &str;
|
const NAME: &str;
|
||||||
|
|||||||
@@ -136,6 +136,7 @@ impl Expr {
|
|||||||
_ => Err(self),
|
_ => Err(self),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub async fn pos(&self) -> Pos { self.data().await.pos.clone() }
|
||||||
pub fn handle(&self) -> Rc<ExprHandle> { self.handle.clone() }
|
pub fn handle(&self) -> Rc<ExprHandle> { self.handle.clone() }
|
||||||
|
|
||||||
pub fn slot(&self) -> GExpr {
|
pub fn slot(&self) -> GExpr {
|
||||||
|
|||||||
@@ -31,6 +31,19 @@ trait_set! {
|
|||||||
trait FunCB = Fn(Vec<Expr>) -> LocalBoxFuture<'static, OrcRes<GExpr>> + 'static;
|
trait FunCB = Fn(Vec<Expr>) -> LocalBoxFuture<'static, OrcRes<GExpr>> + 'static;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
task_local! {
|
||||||
|
static ARGV: Vec<Expr>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_arg(idx: usize) -> Expr {
|
||||||
|
ARGV
|
||||||
|
.try_with(|argv| {
|
||||||
|
(argv.get(idx).cloned())
|
||||||
|
.unwrap_or_else(|| panic!("Cannot read argument ##{idx}, only have {}", argv.len()))
|
||||||
|
})
|
||||||
|
.expect("get_arg called outside ExprFunc")
|
||||||
|
}
|
||||||
|
|
||||||
pub trait ExprFunc<I, O>: Clone + 'static {
|
pub trait ExprFunc<I, O>: Clone + 'static {
|
||||||
fn argtyps() -> &'static [TypeId];
|
fn argtyps() -> &'static [TypeId];
|
||||||
fn apply<'a>(&self, hand: ExecHandle<'a>, v: Vec<Expr>) -> impl Future<Output = OrcRes<GExpr>>;
|
fn apply<'a>(&self, hand: ExecHandle<'a>, v: Vec<Expr>) -> impl Future<Output = OrcRes<GExpr>>;
|
||||||
|
|||||||
@@ -184,12 +184,12 @@ impl ConstCtx {
|
|||||||
&'b self,
|
&'b self,
|
||||||
names: impl IntoIterator<Item = &'b Sym> + 'b,
|
names: impl IntoIterator<Item = &'b Sym> + 'b,
|
||||||
) -> impl Stream<Item = OrcRes<Sym>> + 'b {
|
) -> impl Stream<Item = OrcRes<Sym>> + 'b {
|
||||||
let resolve_names = api::ResolveNames {
|
let names = names.into_iter().map(|n| n.to_api()).collect_vec();
|
||||||
constid: self.constid,
|
|
||||||
sys: sys_id(),
|
|
||||||
names: names.into_iter().map(|n| n.to_api()).collect_vec(),
|
|
||||||
};
|
|
||||||
stream(async |mut cx| {
|
stream(async |mut cx| {
|
||||||
|
if names.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let resolve_names = api::ResolveNames { constid: self.constid, sys: sys_id(), names };
|
||||||
for name_opt in request(resolve_names).await {
|
for name_opt in request(resolve_names).await {
|
||||||
cx.emit(match name_opt {
|
cx.emit(match name_opt {
|
||||||
Err(e) => Err(OrcErrv::from_api(&e).await),
|
Err(e) => Err(OrcErrv::from_api(&e).await),
|
||||||
|
|||||||
@@ -47,8 +47,9 @@ impl ReflMod {
|
|||||||
async fn try_populate(&self) -> Result<(), api::LsModuleError> {
|
async fn try_populate(&self) -> Result<(), api::LsModuleError> {
|
||||||
let path_tok = iv(&self.0.path[..]).await;
|
let path_tok = iv(&self.0.path[..]).await;
|
||||||
let reply = match request(api::LsModule(sys_id(), path_tok.to_api())).await {
|
let reply = match request(api::LsModule(sys_id(), path_tok.to_api())).await {
|
||||||
Err(api::LsModuleError::TreeUnavailable) =>
|
Err(api::LsModuleError::TreeUnavailable) => {
|
||||||
panic!("Reflected tree accessed outside an interpreter call. This extension is faulty."),
|
panic!("Reflected tree accessed outside an interpreter call. This extension is faulty.")
|
||||||
|
},
|
||||||
Err(err) => return Err(err),
|
Err(err) => return Err(err),
|
||||||
Ok(details) => details,
|
Ok(details) => details,
|
||||||
};
|
};
|
||||||
@@ -79,10 +80,12 @@ impl ReflMod {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
match self.try_populate().await {
|
match self.try_populate().await {
|
||||||
Err(api::LsModuleError::InvalidPath) =>
|
Err(api::LsModuleError::InvalidPath) => {
|
||||||
panic!("Path became invalid since module was created"),
|
panic!("Path became invalid since module was created")
|
||||||
Err(api::LsModuleError::IsConstant) =>
|
},
|
||||||
panic!("Path previously contained a module but now contains a constant"),
|
Err(api::LsModuleError::IsConstant) => {
|
||||||
|
panic!("Path previously contained a module but now contains a constant")
|
||||||
|
},
|
||||||
Err(api::LsModuleError::TreeUnavailable) => unreachable!(),
|
Err(api::LsModuleError::TreeUnavailable) => unreachable!(),
|
||||||
Ok(()) => (),
|
Ok(()) => (),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,8 +71,7 @@ pub fn module(
|
|||||||
vec![GenMember { name, kind, public, comments: vec![] }]
|
vec![GenMember { name, kind, public, comments: vec![] }]
|
||||||
}
|
}
|
||||||
pub fn root_mod(name: &str, mems: impl IntoIterator<Item = Vec<GenMember>>) -> (String, MemKind) {
|
pub fn root_mod(name: &str, mems: impl IntoIterator<Item = Vec<GenMember>>) -> (String, MemKind) {
|
||||||
let kind = MemKind::Mod { members: mems.into_iter().flatten().collect() };
|
(name.to_string(), MemKind::module(mems))
|
||||||
(name.to_string(), kind)
|
|
||||||
}
|
}
|
||||||
pub fn fun<I, O>(public: bool, name: &str, xf: impl ExprFunc<I, O>) -> Vec<GenMember> {
|
pub fn fun<I, O>(public: bool, name: &str, xf: impl ExprFunc<I, O>) -> Vec<GenMember> {
|
||||||
let fac =
|
let fac =
|
||||||
@@ -113,12 +112,12 @@ pub fn merge_trivial(trees: impl IntoIterator<Item = Vec<GenMember>>) -> Vec<Gen
|
|||||||
let prev = all_members.insert(mem.name.clone(), (unit, mem.comments.into_iter().collect()));
|
let prev = all_members.insert(mem.name.clone(), (unit, mem.comments.into_iter().collect()));
|
||||||
assert!(prev.is_none(), "Conflict in trivial tree merge on {}", mem.name);
|
assert!(prev.is_none(), "Conflict in trivial tree merge on {}", mem.name);
|
||||||
},
|
},
|
||||||
MemKind::Mod { members } => match all_members.entry(mem.name.clone()) {
|
MemKind::Mod(members) => match all_members.entry(mem.name.clone()) {
|
||||||
hashbrown::hash_map::Entry::Vacant(slot) => {
|
hashbrown::hash_map::Entry::Vacant(slot) => {
|
||||||
slot.insert((MemKind::Mod { members }, mem.comments.into_iter().collect()));
|
slot.insert((MemKind::Mod(members), mem.comments.into_iter().collect()));
|
||||||
},
|
},
|
||||||
hashbrown::hash_map::Entry::Occupied(mut old) => match old.get_mut() {
|
hashbrown::hash_map::Entry::Occupied(mut old) => match old.get_mut() {
|
||||||
(MemKind::Mod { members: old_items, .. }, old_cmts) => {
|
(MemKind::Mod(old_items), old_cmts) => {
|
||||||
let mut swap = vec![];
|
let mut swap = vec![];
|
||||||
std::mem::swap(&mut swap, old_items);
|
std::mem::swap(&mut swap, old_items);
|
||||||
*old_items = merge_trivial([swap, members]);
|
*old_items = merge_trivial([swap, members]);
|
||||||
@@ -167,15 +166,19 @@ impl GenMember {
|
|||||||
|
|
||||||
pub enum MemKind {
|
pub enum MemKind {
|
||||||
Const(GExpr),
|
Const(GExpr),
|
||||||
Mod { members: Vec<GenMember> },
|
Mod(Vec<GenMember>),
|
||||||
Lazy(LazyMemberFactory),
|
Lazy(LazyMemberFactory),
|
||||||
}
|
}
|
||||||
impl MemKind {
|
impl MemKind {
|
||||||
|
pub async fn cnst(val: impl ToExpr) -> Self { Self::Const(val.to_gen().await) }
|
||||||
|
pub fn module(mems: impl IntoIterator<Item = Vec<GenMember>>) -> Self {
|
||||||
|
Self::Mod(mems.into_iter().flatten().collect())
|
||||||
|
}
|
||||||
pub(crate) async fn into_api(self, ctx: &mut impl TreeIntoApiCtx) -> api::MemberKind {
|
pub(crate) async fn into_api(self, ctx: &mut impl TreeIntoApiCtx) -> api::MemberKind {
|
||||||
match self {
|
match self {
|
||||||
Self::Lazy(lazy) => api::MemberKind::Lazy(add_lazy(ctx, lazy)),
|
Self::Lazy(lazy) => api::MemberKind::Lazy(add_lazy(ctx, lazy)),
|
||||||
Self::Const(c) => api::MemberKind::Const(c.serialize().await),
|
Self::Const(c) => api::MemberKind::Const(c.serialize().await),
|
||||||
Self::Mod { members } => api::MemberKind::Module(api::Module {
|
Self::Mod(members) => api::MemberKind::Module(api::Module {
|
||||||
members: stream(async |mut cx| {
|
members: stream(async |mut cx| {
|
||||||
for m in members {
|
for m in members {
|
||||||
cx.emit(m.into_api(ctx).await).await
|
cx.emit(m.into_api(ctx).await).await
|
||||||
|
|||||||
@@ -110,8 +110,9 @@ impl ExecCtx {
|
|||||||
(ExprKind::Identity(val.clone()), StackOp::Swap(val))
|
(ExprKind::Identity(val.clone()), StackOp::Swap(val))
|
||||||
},
|
},
|
||||||
Err(f) => match &*f.kind().read().await {
|
Err(f) => match &*f.kind().read().await {
|
||||||
ExprKind::Arg | ExprKind::Call(..) | ExprKind::Seq(..) | ExprKind::Const(_) =>
|
ExprKind::Arg | ExprKind::Call(..) | ExprKind::Seq(..) | ExprKind::Const(_) => {
|
||||||
panic!("This should not appear outside function bodies"),
|
panic!("This should not appear outside function bodies")
|
||||||
|
},
|
||||||
ExprKind::Missing => panic!("Should have been replaced"),
|
ExprKind::Missing => panic!("Should have been replaced"),
|
||||||
ExprKind::Atom(a) => {
|
ExprKind::Atom(a) => {
|
||||||
let x_norm = self.unpack_ident(&x).await;
|
let x_norm = self.unpack_ident(&x).await;
|
||||||
|
|||||||
@@ -155,8 +155,9 @@ async fn print_exprkind<'a>(
|
|||||||
) -> FmtUnit {
|
) -> FmtUnit {
|
||||||
match &ek {
|
match &ek {
|
||||||
ExprKind::Arg => "Arg".to_string().into(),
|
ExprKind::Arg => "Arg".to_string().into(),
|
||||||
ExprKind::Missing =>
|
ExprKind::Missing => {
|
||||||
panic!("This variant is swapped into write guards, so a read can never see it"),
|
panic!("This variant is swapped into write guards, so a read can never see it")
|
||||||
|
},
|
||||||
ExprKind::Atom(a) => a.print(c).await,
|
ExprKind::Atom(a) => a.print(c).await,
|
||||||
ExprKind::Bottom(e) if e.len() == 1 => format!("Bottom({e})").into(),
|
ExprKind::Bottom(e) if e.len() == 1 => format!("Bottom({e})").into(),
|
||||||
ExprKind::Bottom(e) => format!("Bottom(\n\t{}\n)", indent(&e.to_string())).into(),
|
ExprKind::Bottom(e) => format!("Bottom(\n\t{}\n)", indent(&e.to_string())).into(),
|
||||||
|
|||||||
@@ -211,12 +211,13 @@ impl Extension {
|
|||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
Ok(module) => module,
|
Ok(module) => module,
|
||||||
Err(ChildError { kind, .. }) =>
|
Err(ChildError { kind, .. }) => {
|
||||||
break 'reply Err(match kind {
|
break 'reply Err(match kind {
|
||||||
ChildErrorKind::Private => panic!("Access checking was disabled"),
|
ChildErrorKind::Private => panic!("Access checking was disabled"),
|
||||||
ChildErrorKind::Constant => api::LsModuleError::IsConstant,
|
ChildErrorKind::Constant => api::LsModuleError::IsConstant,
|
||||||
ChildErrorKind::Missing => api::LsModuleError::InvalidPath,
|
ChildErrorKind::Missing => api::LsModuleError::InvalidPath,
|
||||||
}),
|
});
|
||||||
|
},
|
||||||
};
|
};
|
||||||
let mut members = std::collections::HashMap::new();
|
let mut members = std::collections::HashMap::new();
|
||||||
for (k, v) in &module.members {
|
for (k, v) in &module.members {
|
||||||
|
|||||||
@@ -158,14 +158,15 @@ impl System {
|
|||||||
}
|
}
|
||||||
match cmod.imports.get(selector) {
|
match cmod.imports.get(selector) {
|
||||||
Some(Ok(dest)) => return Ok(dest.target.to_vname().suffix(tail.iter().cloned())),
|
Some(Ok(dest)) => return Ok(dest.target.to_vname().suffix(tail.iter().cloned())),
|
||||||
Some(Err(dests)) =>
|
Some(Err(dests)) => {
|
||||||
return Err(mk_errv_floating(
|
return Err(mk_errv_floating(
|
||||||
is("Ambiguous name").await,
|
is("Ambiguous name").await,
|
||||||
format!(
|
format!(
|
||||||
"{selector} could refer to {}",
|
"{selector} could refer to {}",
|
||||||
dests.iter().map(|ri| &ri.target).display("or")
|
dests.iter().map(|ri| &ri.target).display("or")
|
||||||
),
|
),
|
||||||
)),
|
));
|
||||||
|
},
|
||||||
None => (),
|
None => (),
|
||||||
}
|
}
|
||||||
if root_data.root.members.get(selector).is_some() {
|
if root_data.root.members.get(selector).is_some() {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ mod std;
|
|||||||
|
|
||||||
pub use std::number::num_atom::{Float, HomoArray, Int, Num};
|
pub use std::number::num_atom::{Float, HomoArray, Int, Num};
|
||||||
pub use std::option::OrcOpt;
|
pub use std::option::OrcOpt;
|
||||||
|
pub use std::protocol::types::{ProtoBuilder, TagBuilder, proto, type_tag};
|
||||||
pub use std::reflection::sym_atom::{SymAtom, sym_expr};
|
pub use std::reflection::sym_atom::{SymAtom, sym_expr};
|
||||||
pub use std::std_system::StdSystem;
|
pub use std::std_system::StdSystem;
|
||||||
pub use std::string::str_atom::OrcString;
|
pub use std::string::str_atom::OrcString;
|
||||||
|
|||||||
@@ -14,17 +14,36 @@ use crate::{HomoTpl, UntypedTuple};
|
|||||||
pub async fn gen_macro_lib() -> Vec<GenMember> {
|
pub async fn gen_macro_lib() -> Vec<GenMember> {
|
||||||
prefix("macros", [
|
prefix("macros", [
|
||||||
fun(true, "resolve", async |tpl: TAtom<MacTree>| resolve(own(&tpl).await).await),
|
fun(true, "resolve", async |tpl: TAtom<MacTree>| resolve(own(&tpl).await).await),
|
||||||
// TODO test whether any of this worked
|
|
||||||
prefix("common", [
|
prefix("common", [
|
||||||
build_macro(None, ["..", "_"]).finish(),
|
build_macro(None, ["..", "_"]).finish(),
|
||||||
build_macro(Some(1), ["+"])
|
build_macro(Some(1), ["+"])
|
||||||
.rule(mactreev!("...$" lhs 0 macros::common::+ "...$" rhs 1), [async |[lhs, rhs]| {
|
.rule(mactreev!("...$" lhs 1 macros::common::+ "...$" rhs 0), [async |[lhs, rhs]| {
|
||||||
call(sym_ref(sym!(std::number::add)), [resolve(lhs).await, resolve(rhs).await])
|
call(sym_ref(sym!(std::ops::add::resolve)), [resolve(lhs).await, resolve(rhs).await])
|
||||||
|
}])
|
||||||
|
.finish(),
|
||||||
|
build_macro(Some(1), ["-"])
|
||||||
|
.rule(mactreev!("...$" lhs 1 macros::common::- "...$" rhs 0), [async |[lhs, rhs]| {
|
||||||
|
call(sym_ref(sym!(std::ops::sub::resolve)), [resolve(lhs).await, resolve(rhs).await])
|
||||||
}])
|
}])
|
||||||
.finish(),
|
.finish(),
|
||||||
build_macro(Some(2), ["*"])
|
build_macro(Some(2), ["*"])
|
||||||
.rule(mactreev!("...$" lhs 0 macros::common::* "...$" rhs 1), [async |[lhs, rhs]| {
|
.rule(mactreev!("...$" lhs 1 macros::common::* "...$" rhs 0), [async |[lhs, rhs]| {
|
||||||
call(sym_ref(sym!(std::number::mul)), [resolve(lhs).await, resolve(rhs).await])
|
call(sym_ref(sym!(std::ops::mul::resolve)), [resolve(lhs).await, resolve(rhs).await])
|
||||||
|
}])
|
||||||
|
.finish(),
|
||||||
|
build_macro(Some(2), ["/"])
|
||||||
|
.rule(mactreev!("...$" lhs 1 macros::common::/ "...$" rhs 0), [async |[lhs, rhs]| {
|
||||||
|
call(sym_ref(sym!(std::ops::div::resolve)), [resolve(lhs).await, resolve(rhs).await])
|
||||||
|
}])
|
||||||
|
.finish(),
|
||||||
|
build_macro(Some(2), ["%"])
|
||||||
|
.rule(mactreev!("...$" lhs 1 macros::common::% "...$" rhs 0), [async |[lhs, rhs]| {
|
||||||
|
call(sym_ref(sym!(std::ops::mod::resolve)), [resolve(lhs).await, resolve(rhs).await])
|
||||||
|
}])
|
||||||
|
.finish(),
|
||||||
|
build_macro(Some(10), ["."])
|
||||||
|
.rule(mactreev!("...$" lhs 1 macros::common::. "...$" rhs 0), [async |[lhs, rhs]| {
|
||||||
|
call(sym_ref(sym!(std::ops::get::resolve)), [resolve(lhs).await, resolve(rhs).await])
|
||||||
}])
|
}])
|
||||||
.finish(),
|
.finish(),
|
||||||
build_macro(None, ["comma_list", ","])
|
build_macro(None, ["comma_list", ","])
|
||||||
|
|||||||
@@ -123,12 +123,13 @@ async fn mk_scalar(pattern: &MacTree) -> OrcRes<ScalMatcher> {
|
|||||||
PhKind::Scalar => ScalMatcher::Placeh { key: name.clone() },
|
PhKind::Scalar => ScalMatcher::Placeh { key: name.clone() },
|
||||||
},
|
},
|
||||||
MacTok::S(c, body) => ScalMatcher::S(*c, Box::new(mk_any(&body.items).boxed_local().await?)),
|
MacTok::S(c, body) => ScalMatcher::S(*c, Box::new(mk_any(&body.items).boxed_local().await?)),
|
||||||
MacTok::Lambda(..) =>
|
MacTok::Lambda(..) => {
|
||||||
return Err(mk_errv(
|
return Err(mk_errv(
|
||||||
is("Lambda in matcher").await,
|
is("Lambda in matcher").await,
|
||||||
"Lambdas can't be matched for, only generated in templates",
|
"Lambdas can't be matched for, only generated in templates",
|
||||||
[pattern.pos()],
|
[pattern.pos()],
|
||||||
)),
|
));
|
||||||
|
},
|
||||||
MacTok::Value(_) | MacTok::Slot => panic!("Only used for templating"),
|
MacTok::Value(_) | MacTok::Slot => panic!("Only used for templating"),
|
||||||
MacTok::Bottom(errv) => return Err(errv.clone()),
|
MacTok::Bottom(errv) => return Err(errv.clone()),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -95,6 +95,30 @@ pub async fn gen_std_macro_lib() -> Vec<GenMember> {
|
|||||||
.finish(),
|
.finish(),
|
||||||
fun(false, "matcher_body", tuple_matcher_body),
|
fun(false, "matcher_body", tuple_matcher_body),
|
||||||
]),
|
]),
|
||||||
|
prefix("record", [
|
||||||
|
build_macro(None, ["r"])
|
||||||
|
.rule(mactreev!(std::record::r[ "...$" elements 0 ]), [async |[elements]: [_;_]| {
|
||||||
|
exec(async move |mut h| {
|
||||||
|
let tup = h
|
||||||
|
.exec::<HomoTpl<TAtom<MacTree>>>(call(sym_ref(sym!(macros::resolve)), [
|
||||||
|
mactree!((macros::common::comma_list "push" elements ;)).to_gen().await,
|
||||||
|
]))
|
||||||
|
.await?;
|
||||||
|
let val = stream::iter(&tup.0[..])
|
||||||
|
.fold(sym_ref(sym!(std::tuple::empty)), async |head, new| {
|
||||||
|
call(sym_ref(sym!(std::tuple::cat)), [
|
||||||
|
head,
|
||||||
|
call(sym_ref(sym!(std::tuple::one)), [call(
|
||||||
|
sym_ref(sym!(macros::resolve)),
|
||||||
|
[new.clone().to_gen().await],
|
||||||
|
)]),
|
||||||
|
])
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
Ok(val)
|
||||||
|
}).await
|
||||||
|
}]).finish(),
|
||||||
|
])
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
pub mod number;
|
pub mod number;
|
||||||
|
pub mod ops;
|
||||||
pub mod option;
|
pub mod option;
|
||||||
pub mod protocol;
|
pub mod protocol;
|
||||||
pub mod record;
|
pub mod record;
|
||||||
|
|||||||
@@ -4,14 +4,18 @@ use orchid_base::error::OrcRes;
|
|||||||
use orchid_base::format::FmtUnit;
|
use orchid_base::format::FmtUnit;
|
||||||
use orchid_base::name::Sym;
|
use orchid_base::name::Sym;
|
||||||
use orchid_base::number::Numeric;
|
use orchid_base::number::Numeric;
|
||||||
use orchid_extension::atom::{AtomFactory, Atomic, AtomicFeatures, Supports, TAtom, ToAtom};
|
use orchid_base::sym;
|
||||||
|
use orchid_extension::atom::{
|
||||||
|
AtomFactory, Atomic, AtomicFeatures, MethodSetBuilder, Supports, TAtom, ToAtom,
|
||||||
|
};
|
||||||
use orchid_extension::atom_thin::{ThinAtom, ThinVariant};
|
use orchid_extension::atom_thin::{ThinAtom, ThinVariant};
|
||||||
use orchid_extension::conv::TryFromExpr;
|
use orchid_extension::conv::TryFromExpr;
|
||||||
use orchid_extension::expr::Expr;
|
use orchid_extension::expr::Expr;
|
||||||
|
use orchid_extension::gen_expr::sym_ref;
|
||||||
use ordered_float::NotNan;
|
use ordered_float::NotNan;
|
||||||
use rust_decimal::prelude::Zero;
|
use rust_decimal::prelude::Zero;
|
||||||
|
|
||||||
use crate::std::protocol::types::GetTagIdMethod;
|
use crate::std::protocol::types::{GetImplMethod, GetTagIdMethod};
|
||||||
use crate::std::string::to_string::ToStringMethod;
|
use crate::std::string::to_string::ToStringMethod;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Coding)]
|
#[derive(Clone, Debug, Coding)]
|
||||||
@@ -19,6 +23,12 @@ pub struct Int(pub i64);
|
|||||||
impl Atomic for Int {
|
impl Atomic for Int {
|
||||||
type Variant = ThinVariant;
|
type Variant = ThinVariant;
|
||||||
type Data = Self;
|
type Data = Self;
|
||||||
|
fn reg_reqs() -> MethodSetBuilder<Self> {
|
||||||
|
MethodSetBuilder::new()
|
||||||
|
.handle::<GetTagIdMethod>()
|
||||||
|
.handle::<GetImplMethod>()
|
||||||
|
.handle::<ToStringMethod>()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
impl ThinAtom for Int {
|
impl ThinAtom for Int {
|
||||||
async fn print(&self) -> FmtUnit { self.0.to_string().into() }
|
async fn print(&self) -> FmtUnit { self.0.to_string().into() }
|
||||||
@@ -33,6 +43,25 @@ impl Supports<GetTagIdMethod> for Int {
|
|||||||
Sym::parse("std::number::Int").await.unwrap().to_api()
|
Sym::parse("std::number::Int").await.unwrap().to_api()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl Supports<GetImplMethod> for Int {
|
||||||
|
async fn handle(&self, req: GetImplMethod) -> <GetImplMethod as Request>::Response {
|
||||||
|
let name = Sym::from_api(req.0).await;
|
||||||
|
let val = if name == sym!(std::ops::add) {
|
||||||
|
sym_ref(sym!(std::number::add))
|
||||||
|
} else if name == sym!(std::ops::sub) {
|
||||||
|
sym_ref(sym!(std::number::sub))
|
||||||
|
} else if name == sym!(std::ops::mul) {
|
||||||
|
sym_ref(sym!(std::number::mul))
|
||||||
|
} else if name == sym!(std::ops::div) {
|
||||||
|
sym_ref(sym!(std::number::idiv))
|
||||||
|
} else if name == sym!(std::ops::mod) {
|
||||||
|
sym_ref(sym!(std::number::imod))
|
||||||
|
} else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
Some(val.create().await.serialize().await)
|
||||||
|
}
|
||||||
|
}
|
||||||
impl Supports<ToStringMethod> for Int {
|
impl Supports<ToStringMethod> for Int {
|
||||||
async fn handle(&self, _: ToStringMethod) -> <ToStringMethod as Request>::Response {
|
async fn handle(&self, _: ToStringMethod) -> <ToStringMethod as Request>::Response {
|
||||||
self.0.to_string()
|
self.0.to_string()
|
||||||
@@ -44,6 +73,12 @@ pub struct Float(pub NotNan<f64>);
|
|||||||
impl Atomic for Float {
|
impl Atomic for Float {
|
||||||
type Variant = ThinVariant;
|
type Variant = ThinVariant;
|
||||||
type Data = Self;
|
type Data = Self;
|
||||||
|
fn reg_reqs() -> MethodSetBuilder<Self> {
|
||||||
|
MethodSetBuilder::new()
|
||||||
|
.handle::<GetTagIdMethod>()
|
||||||
|
.handle::<GetImplMethod>()
|
||||||
|
.handle::<ToStringMethod>()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
impl ThinAtom for Float {
|
impl ThinAtom for Float {
|
||||||
async fn print(&self) -> FmtUnit { self.0.to_string().into() }
|
async fn print(&self) -> FmtUnit { self.0.to_string().into() }
|
||||||
@@ -53,6 +88,30 @@ impl TryFromExpr for Float {
|
|||||||
Ok(Self(Num::try_from_expr(expr).await?.0.to_f64()))
|
Ok(Self(Num::try_from_expr(expr).await?.0.to_f64()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl Supports<GetTagIdMethod> for Float {
|
||||||
|
async fn handle(&self, _: GetTagIdMethod) -> <GetTagIdMethod as Request>::Response {
|
||||||
|
Sym::parse("std::number::Float").await.unwrap().to_api()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Supports<GetImplMethod> for Float {
|
||||||
|
async fn handle(&self, req: GetImplMethod) -> <GetImplMethod as Request>::Response {
|
||||||
|
let name = Sym::from_api(req.0).await;
|
||||||
|
let val = if name == sym!(std::ops::add) {
|
||||||
|
sym_ref(sym!(std::number::add))
|
||||||
|
} else if name == sym!(std::ops::sub) {
|
||||||
|
sym_ref(sym!(std::number::sub))
|
||||||
|
} else if name == sym!(std::ops::mul) {
|
||||||
|
sym_ref(sym!(std::number::mul))
|
||||||
|
} else if name == sym!(std::ops::div) {
|
||||||
|
sym_ref(sym!(std::number::fdiv))
|
||||||
|
} else if name == sym!(std::ops::mod) {
|
||||||
|
sym_ref(sym!(std::number::fmod))
|
||||||
|
} else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
Some(val.create().await.serialize().await)
|
||||||
|
}
|
||||||
|
}
|
||||||
impl Supports<ToStringMethod> for Float {
|
impl Supports<ToStringMethod> for Float {
|
||||||
async fn handle(&self, _: ToStringMethod) -> <ToStringMethod as Request>::Response {
|
async fn handle(&self, _: ToStringMethod) -> <ToStringMethod as Request>::Response {
|
||||||
self.0.to_string()
|
self.0.to_string()
|
||||||
|
|||||||
@@ -1,34 +1,60 @@
|
|||||||
|
use orchid_base::error::mk_errv;
|
||||||
|
use orchid_base::interner::is;
|
||||||
use orchid_base::number::Numeric;
|
use orchid_base::number::Numeric;
|
||||||
|
use orchid_extension::func_atom::get_arg;
|
||||||
use orchid_extension::tree::{GenMember, fun, prefix};
|
use orchid_extension::tree::{GenMember, fun, prefix};
|
||||||
use ordered_float::NotNan;
|
use ordered_float::NotNan;
|
||||||
|
use rust_decimal::prelude::ToPrimitive;
|
||||||
|
|
||||||
use super::num_atom::{Float, HomoArray, Int, Num};
|
use super::num_atom::{Float, HomoArray, Int, Num};
|
||||||
|
|
||||||
pub fn gen_num_lib() -> Vec<GenMember> {
|
pub fn gen_num_lib() -> Vec<GenMember> {
|
||||||
prefix("std::number", [
|
prefix("std::number", [
|
||||||
fun(true, "add", async |a: Num, b: Num| {
|
fun(false, "add", async |a: Num, b: Num| {
|
||||||
Num(match HomoArray::new([a.0, b.0]) {
|
Num(match HomoArray::new([a.0, b.0]) {
|
||||||
HomoArray::Int([a, b]) => Numeric::Int(a + b),
|
HomoArray::Int([a, b]) => Numeric::Int(a + b),
|
||||||
HomoArray::Float([a, b]) => Numeric::Float(a + b),
|
HomoArray::Float([a, b]) => Numeric::Float(a + b),
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
fun(true, "neg", async |a: Num| {
|
fun(false, "sub", async |a: Num, b: Num| {
|
||||||
|
Num(match HomoArray::new([a.0, b.0]) {
|
||||||
|
HomoArray::Int([a, b]) => Numeric::Int(a - b),
|
||||||
|
HomoArray::Float([a, b]) => Numeric::Float(a - b),
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
fun(false, "neg", async |a: Num| {
|
||||||
Num(match a.0 {
|
Num(match a.0 {
|
||||||
Numeric::Int(i) => Numeric::Int(-i),
|
Numeric::Int(i) => Numeric::Int(-i),
|
||||||
Numeric::Float(f) => Numeric::Float(-f),
|
Numeric::Float(f) => Numeric::Float(-f),
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
fun(true, "mul", async |a: Num, b: Num| {
|
fun(false, "mul", async |a: Num, b: Num| {
|
||||||
Num(match HomoArray::new([a.0, b.0]) {
|
Num(match HomoArray::new([a.0, b.0]) {
|
||||||
HomoArray::Int([a, b]) => Numeric::Int(a * b),
|
HomoArray::Int([a, b]) => Numeric::Int(a * b),
|
||||||
HomoArray::Float([a, b]) => Numeric::Float(a * b),
|
HomoArray::Float([a, b]) => Numeric::Float(a * b),
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
fun(true, "idiv", async |a: Int, b: Int| Int(a.0 / b.0)),
|
fun(false, "idiv", async |a: Int, b: Int| Int(a.0 / b.0)),
|
||||||
fun(true, "imod", async |a: Int, b: Int| Int(a.0 % b.0)),
|
fun(false, "imod", async |a: Int, b: Int| Int(a.0 % b.0)),
|
||||||
fun(true, "fdiv", async |a: Float, b: Float| Float(a.0 / b.0)),
|
fun(false, "fdiv", async |a: Float, b: Float| Float(a.0 / b.0)),
|
||||||
fun(true, "fmod", async |a: Float, b: Float| {
|
fun(false, "fmod", async |a: Float, b: Float| {
|
||||||
Float(a.0 - NotNan::new((a.0 / b.0).trunc()).unwrap() * b.0)
|
Float(a.0 - NotNan::new((a.0 / b.0).trunc()).unwrap() * b.0)
|
||||||
}),
|
}),
|
||||||
|
fun(false, "to_i", async |a: Num| {
|
||||||
|
Ok(Int(match a.0 {
|
||||||
|
Numeric::Int(i) => i,
|
||||||
|
Numeric::Float(f) => match f.to_i64() {
|
||||||
|
Some(i) => i,
|
||||||
|
None => {
|
||||||
|
return Err(mk_errv(
|
||||||
|
is("Float out of range").await,
|
||||||
|
format!("{f} is not representable as an integer"),
|
||||||
|
[get_arg(0).pos().await],
|
||||||
|
));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
}),
|
||||||
|
fun(false, "to_f", async |a: Num| Float(a.0.to_f64())),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|||||||
36
orchid-std/src/std/ops/mod.rs
Normal file
36
orchid-std/src/std/ops/mod.rs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
use orchid_extension::tree::{GenMember, comments, prefix};
|
||||||
|
|
||||||
|
use crate::proto;
|
||||||
|
|
||||||
|
pub fn gen_ops_lib() -> Vec<GenMember> {
|
||||||
|
prefix("std::ops", [
|
||||||
|
comments(
|
||||||
|
["Protocol for the infix + operator", "|type: self -> rhs -> self|"],
|
||||||
|
proto(true, "add").finish(),
|
||||||
|
),
|
||||||
|
comments(
|
||||||
|
["Protocol for the infix - operator", "|type: self -> rhs -> self|"],
|
||||||
|
proto(true, "sub").finish(),
|
||||||
|
),
|
||||||
|
comments(
|
||||||
|
["Protocol for the infix * operator", "|type: self -> rhs -> self|"],
|
||||||
|
proto(true, "mul").finish(),
|
||||||
|
),
|
||||||
|
comments(
|
||||||
|
["Protocol for the infix / operator", "|type: self -> rhs -> self|"],
|
||||||
|
proto(true, "div").finish(),
|
||||||
|
),
|
||||||
|
comments(
|
||||||
|
["Protocol for the infix % operator", "|type: self -> rhs -> self|"],
|
||||||
|
proto(true, "mod").finish(),
|
||||||
|
),
|
||||||
|
comments(
|
||||||
|
["Protocol used by paths for reading", "|type: self -> key -> value|"],
|
||||||
|
proto(true, "get").finish(),
|
||||||
|
),
|
||||||
|
comments(
|
||||||
|
["Protocol used by paths for writing", "|type: self -> key -> value -> self|"],
|
||||||
|
proto(true, "set").finish(),
|
||||||
|
),
|
||||||
|
])
|
||||||
|
}
|
||||||
@@ -18,17 +18,19 @@ pub async fn parse_impls(
|
|||||||
) -> OrcRes<()> {
|
) -> OrcRes<()> {
|
||||||
let body = match &body_tt.tok {
|
let body = match &body_tt.tok {
|
||||||
Token::S(Paren::Round, body) => line_items(Snippet::new(body_tt, body)).await,
|
Token::S(Paren::Round, body) => line_items(Snippet::new(body_tt, body)).await,
|
||||||
Token::S(ptyp, _) =>
|
Token::S(ptyp, _) => {
|
||||||
return Err(mk_errv(
|
return Err(mk_errv(
|
||||||
is("Incorrect paren type").await,
|
is("Incorrect paren type").await,
|
||||||
format!("Expected () block, found {ptyp}"),
|
format!("Expected () block, found {ptyp}"),
|
||||||
[body_tt.sr().pos()],
|
[body_tt.sr().pos()],
|
||||||
)),
|
));
|
||||||
_ =>
|
},
|
||||||
|
_ => {
|
||||||
return Err(
|
return Err(
|
||||||
token_errv(body_tt, "Expected body", |s| format!("Expected (impl ...) block, found {s}"))
|
token_errv(body_tt, "Expected body", |s| format!("Expected (impl ...) block, found {s}"))
|
||||||
.await,
|
.await,
|
||||||
),
|
);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
for Parsed { tail: line, output: comments } in body {
|
for Parsed { tail: line, output: comments } in body {
|
||||||
if let Ok(Parsed { tail, .. }) = expect_tok(line, is("impl").await).await {
|
if let Ok(Parsed { tail, .. }) = expect_tok(line, is("impl").await).await {
|
||||||
@@ -37,18 +39,20 @@ pub async fn parse_impls(
|
|||||||
Ok(None) => panic!("multiname is always at least one name"),
|
Ok(None) => panic!("multiname is always at least one name"),
|
||||||
Ok(Some(ref n @ Import { name: Some(_), ref sr, .. })) =>
|
Ok(Some(ref n @ Import { name: Some(_), ref sr, .. })) =>
|
||||||
(n.clone().mspath().to_sym().await, sr.clone()),
|
(n.clone().mspath().to_sym().await, sr.clone()),
|
||||||
Ok(Some(Import { name: None, sr, .. })) =>
|
Ok(Some(Import { name: None, sr, .. })) => {
|
||||||
return Err(mk_errv(
|
return Err(mk_errv(
|
||||||
is("impl line with globstar").await,
|
is("impl line with globstar").await,
|
||||||
"::* is not permitted in a protocol impl",
|
"::* is not permitted in a protocol impl",
|
||||||
[sr.pos()],
|
[sr.pos()],
|
||||||
)),
|
));
|
||||||
Err(e) =>
|
},
|
||||||
|
Err(e) => {
|
||||||
return Err(mk_errv(
|
return Err(mk_errv(
|
||||||
is("Impl line with multiple protocol names").await,
|
is("Impl line with multiple protocol names").await,
|
||||||
"::() is not permitted in a protocol impl",
|
"::() is not permitted in a protocol impl",
|
||||||
e.map(|i| i.sr.pos()),
|
e.map(|i| i.sr.pos()),
|
||||||
)),
|
));
|
||||||
|
},
|
||||||
};
|
};
|
||||||
let Parsed { tail, .. } = expect_tok(tail, is("as").await).await?;
|
let Parsed { tail, .. } = expect_tok(tail, is("as").await).await?;
|
||||||
let cnst_name = is(&format!("{}{}", lines.len(), name.iter().join("__"))).await;
|
let cnst_name = is(&format!("{}{}", lines.len(), name.iter().join("__"))).await;
|
||||||
|
|||||||
@@ -1,22 +1,29 @@
|
|||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use futures::FutureExt;
|
||||||
|
use futures::future::{LocalBoxFuture, join_all};
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
|
use itertools::Itertools;
|
||||||
use never::Never;
|
use never::Never;
|
||||||
use orchid_api_derive::Coding;
|
use orchid_api_derive::{Coding, Hierarchy};
|
||||||
use orchid_api_traits::Request;
|
use orchid_api_traits::Request;
|
||||||
use orchid_base::error::{OrcRes, mk_errv};
|
use orchid_base::error::{OrcRes, mk_errv};
|
||||||
use orchid_base::format::fmt;
|
use orchid_base::format::fmt;
|
||||||
use orchid_base::interner::is;
|
use orchid_base::interner::{ev, is};
|
||||||
use orchid_base::name::Sym;
|
use orchid_base::name::{NameLike, Sym, VName};
|
||||||
use orchid_extension::atom::{AtomMethod, Atomic, ForeignAtom, MethodSetBuilder, Supports, TAtom};
|
use orchid_extension::atom::{AtomMethod, Atomic, ForeignAtom, MethodSetBuilder, Supports, TAtom};
|
||||||
use orchid_extension::atom_owned::{OwnedAtom, OwnedVariant, own};
|
use orchid_extension::atom_owned::{OwnedAtom, OwnedVariant, own};
|
||||||
use orchid_extension::conv::ToExpr;
|
use orchid_extension::conv::{ClonableToExprDyn, ToExpr};
|
||||||
use orchid_extension::expr::Expr;
|
use orchid_extension::coroutine_exec::exec;
|
||||||
use orchid_extension::gen_expr::call;
|
use orchid_extension::expr::{Expr, ExprHandle};
|
||||||
use orchid_extension::tree::{GenMember, fun, prefix};
|
use orchid_extension::gen_expr::{GExpr, call, sym_ref};
|
||||||
|
use orchid_extension::system::dep_req;
|
||||||
|
use orchid_extension::tree::{GenMember, MemKind, cnst, fun, lazy, prefix};
|
||||||
|
|
||||||
use crate::api;
|
use crate::std::std_system::StdReq;
|
||||||
|
use crate::{StdSystem, api};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Tag {
|
pub struct Tag {
|
||||||
@@ -26,17 +33,25 @@ pub struct Tag {
|
|||||||
impl Atomic for Tag {
|
impl Atomic for Tag {
|
||||||
type Data = api::TStrv;
|
type Data = api::TStrv;
|
||||||
type Variant = OwnedVariant;
|
type Variant = OwnedVariant;
|
||||||
fn reg_reqs() -> MethodSetBuilder<Self> { MethodSetBuilder::new().handle::<GetImplMethod>() }
|
fn reg_reqs() -> MethodSetBuilder<Self> {
|
||||||
|
MethodSetBuilder::new().handle::<GetTagIdMethod>().handle::<GetImplMethod>()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
impl OwnedAtom for Tag {
|
impl OwnedAtom for Tag {
|
||||||
type Refs = Never;
|
type Refs = Never;
|
||||||
async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(self.id.to_api()) }
|
async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(self.id.to_api()) }
|
||||||
}
|
}
|
||||||
|
impl Supports<GetTagIdMethod> for Tag {
|
||||||
|
async fn handle(&self, _: GetTagIdMethod) -> <GetTagIdMethod as Request>::Response {
|
||||||
|
self.id.to_api()
|
||||||
|
}
|
||||||
|
}
|
||||||
impl Supports<GetImplMethod> for Tag {
|
impl Supports<GetImplMethod> for Tag {
|
||||||
async fn handle(&self, req: GetImplMethod) -> <GetImplMethod as Request>::Response {
|
async fn handle(&self, req: GetImplMethod) -> <GetImplMethod as Request>::Response {
|
||||||
self.impls.get(&Sym::from_api(req.0).await).map(|expr| expr.handle().ticket())
|
self.impls.get(&Sym::from_api(req.0).await).map(|expr| expr.handle().ticket())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Coding)]
|
#[derive(Clone, Debug, Coding)]
|
||||||
pub struct GetImplMethod(pub api::TStrv);
|
pub struct GetImplMethod(pub api::TStrv);
|
||||||
impl Request for GetImplMethod {
|
impl Request for GetImplMethod {
|
||||||
@@ -75,14 +90,16 @@ impl Supports<GetImplMethod> for Tagged {
|
|||||||
|
|
||||||
pub async fn get_impl(receiver: ForeignAtom, proto: ForeignAtom) -> OrcRes<Expr> {
|
pub async fn get_impl(receiver: ForeignAtom, proto: ForeignAtom) -> OrcRes<Expr> {
|
||||||
let Some(proto_id) = proto.request(GetTagIdMethod).await else {
|
let Some(proto_id) = proto.request(GetTagIdMethod).await else {
|
||||||
return Err(mk_errv(is("Not a protocol").await, "Protocol does not have a tag ID", [
|
return Err(mk_errv(
|
||||||
proto.pos()
|
is("Not a protocol").await,
|
||||||
]));
|
format!("Protocol ({}) does not have a tag ID", fmt(&proto).await),
|
||||||
|
[proto.pos()],
|
||||||
|
));
|
||||||
};
|
};
|
||||||
let Some(impl_val_opt) = receiver.request(GetImplMethod(proto_id)).await else {
|
let Some(impl_val_opt) = receiver.request(GetImplMethod(proto_id)).await else {
|
||||||
return Err(mk_errv(
|
return Err(mk_errv(
|
||||||
is("Receiver not tagged").await,
|
is("Receiver not tagged").await,
|
||||||
"The receiver does not have a type tag",
|
format!("The receiver ({}) does not have a type tag", fmt(&receiver).await),
|
||||||
[receiver.pos()],
|
[receiver.pos()],
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
@@ -92,14 +109,14 @@ pub async fn get_impl(receiver: ForeignAtom, proto: ForeignAtom) -> OrcRes<Expr>
|
|||||||
let Some(type_id) = receiver.request(GetTagIdMethod).await else {
|
let Some(type_id) = receiver.request(GetTagIdMethod).await else {
|
||||||
return Err(mk_errv(
|
return Err(mk_errv(
|
||||||
is("Incorrect protocols implementation in extension").await,
|
is("Incorrect protocols implementation in extension").await,
|
||||||
"Atom provides an impl table but no tag ID",
|
format!("The receiver ({}) provides an impl table but no tag ID", fmt(&receiver).await),
|
||||||
[receiver.pos()],
|
[receiver.pos()],
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
let Some(impl_val_opt) = proto.request(GetImplMethod(type_id)).await else {
|
let Some(impl_val_opt) = proto.request(GetImplMethod(type_id)).await else {
|
||||||
return Err(mk_errv(
|
return Err(mk_errv(
|
||||||
is("Incorrect protocols implementation in extension").await,
|
is("Incorrect protocols implementation in extension").await,
|
||||||
"Proto table atom provides a tag ID but no impl table",
|
format!("Protocol ({}) provides a tag ID but no impl table", fmt(&proto).await),
|
||||||
[receiver.pos()],
|
[receiver.pos()],
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
@@ -108,7 +125,7 @@ pub async fn get_impl(receiver: ForeignAtom, proto: ForeignAtom) -> OrcRes<Expr>
|
|||||||
}
|
}
|
||||||
return Err(mk_errv(
|
return Err(mk_errv(
|
||||||
is("Implementation not found").await,
|
is("Implementation not found").await,
|
||||||
"This protocol is not implemented for this receiver",
|
format!("Protocol {} is not implemented for {}", ev(proto_id).await, ev(type_id).await),
|
||||||
[receiver.pos(), proto.pos()],
|
[receiver.pos(), proto.pos()],
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@@ -134,3 +151,107 @@ pub fn gen_protocol_lib() -> Vec<GenMember> {
|
|||||||
}),
|
}),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Coding, Hierarchy)]
|
||||||
|
#[extends(StdReq)]
|
||||||
|
pub struct CreateTag {
|
||||||
|
pub name: api::TStrv,
|
||||||
|
pub impls: std::collections::HashMap<api::TStrv, api::ExprTicket>,
|
||||||
|
}
|
||||||
|
impl Request for CreateTag {
|
||||||
|
type Response = api::ExprTicket;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn type_tag<'a>(name: &str) -> TagBuilder<'a> {
|
||||||
|
TagBuilder { name: name.to_owned(), impls: HashMap::default() }
|
||||||
|
}
|
||||||
|
pub struct TagBuilder<'a> {
|
||||||
|
name: String,
|
||||||
|
impls: HashMap<String, LocalBoxFuture<'a, GExpr>>,
|
||||||
|
}
|
||||||
|
impl<'a> TagBuilder<'a> {
|
||||||
|
pub fn add_impl(&mut self, name: &str, val: impl ToExpr + 'a) {
|
||||||
|
self.impls.insert(name.to_owned(), val.to_gen().boxed_local());
|
||||||
|
}
|
||||||
|
pub fn with_impl(mut self, name: &str, val: impl ToExpr + 'a) -> Self {
|
||||||
|
self.add_impl(name, val);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
pub async fn finish(self) -> TAtom<Tag> {
|
||||||
|
let tk = dep_req::<StdSystem, _>(CreateTag {
|
||||||
|
name: Sym::parse(&self.name).await.unwrap().to_api(),
|
||||||
|
impls: join_all(self.impls.into_iter().map(|(s, fut)| async move {
|
||||||
|
(
|
||||||
|
Sym::parse(&s).await.unwrap().to_api(),
|
||||||
|
fut.await.create().await.handle().serialize().await,
|
||||||
|
)
|
||||||
|
}))
|
||||||
|
.await
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
TAtom::downcast(ExprHandle::deserialize(tk)).await.unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn proto(public: bool, name: &str) -> ProtoBuilder {
|
||||||
|
ProtoBuilder { public, name: name.to_owned(), impls: HashMap::new(), body: Vec::new() }
|
||||||
|
}
|
||||||
|
pub struct ProtoBuilder {
|
||||||
|
public: bool,
|
||||||
|
name: String,
|
||||||
|
impls: HashMap<String, Box<dyn ClonableToExprDyn>>,
|
||||||
|
body: Vec<GenMember>,
|
||||||
|
}
|
||||||
|
impl ProtoBuilder {
|
||||||
|
pub fn add_impl(&mut self, name: &str, val: impl ToExpr + Clone + 'static) {
|
||||||
|
self.impls.insert(name.to_owned(), Box::new(val));
|
||||||
|
}
|
||||||
|
pub fn with_impl(mut self, name: &str, val: impl ToExpr + Clone + 'static) -> Self {
|
||||||
|
self.add_impl(name, val);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
pub fn add_body(&mut self, members: impl IntoIterator<Item = GenMember>) {
|
||||||
|
self.body.extend(members);
|
||||||
|
}
|
||||||
|
pub fn with_body(mut self, members: impl IntoIterator<Item = GenMember>) -> Self {
|
||||||
|
self.add_body(members);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
pub fn finish(self) -> Vec<GenMember> {
|
||||||
|
lazy(self.public, &self.name, async |path| {
|
||||||
|
let mut tag = type_tag(&path.segs().join("::"));
|
||||||
|
for (name, value) in self.impls {
|
||||||
|
tag.add_impl(&name, value.to_expr().await);
|
||||||
|
}
|
||||||
|
MemKind::module([
|
||||||
|
cnst(true, "__protocol_tag__", tag.finish().await),
|
||||||
|
fun(true, "resolve", resolver_for(path.to_vname())),
|
||||||
|
])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resolver_for(proto: VName) -> impl AsyncFn(ForeignAtom) -> GExpr + Clone {
|
||||||
|
let proto_cache = RefCell::new(None);
|
||||||
|
async move |atom| {
|
||||||
|
let proto_cache = proto_cache.clone();
|
||||||
|
let proto = proto.clone();
|
||||||
|
exec(async move |mut h| {
|
||||||
|
let cached_proto = proto_cache.borrow().as_ref().cloned();
|
||||||
|
let proto = match cached_proto {
|
||||||
|
Some(val) => val,
|
||||||
|
None => {
|
||||||
|
let proto: ForeignAtom = h
|
||||||
|
.exec(sym_ref(proto.clone().suffix([is("__protocol_tag__").await]).to_sym().await))
|
||||||
|
.await?;
|
||||||
|
*proto_cache.borrow_mut() = Some(proto.clone());
|
||||||
|
proto
|
||||||
|
},
|
||||||
|
};
|
||||||
|
Ok(call(get_impl(atom.clone(), proto).await?.to_gen().await, [atom.to_gen().await]))
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,13 +5,17 @@ use std::rc::Rc;
|
|||||||
use futures::AsyncWrite;
|
use futures::AsyncWrite;
|
||||||
use futures::future::join_all;
|
use futures::future::join_all;
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use orchid_api_traits::Encode;
|
use orchid_api_traits::{Encode, Request};
|
||||||
use orchid_base::interner::{IStr, es};
|
use orchid_base::interner::{IStr, es};
|
||||||
use orchid_extension::atom::Atomic;
|
use orchid_base::name::Sym;
|
||||||
|
use orchid_base::sym;
|
||||||
|
use orchid_extension::atom::{Atomic, Supports};
|
||||||
use orchid_extension::atom_owned::{DeserializeCtx, OwnedAtom, OwnedVariant};
|
use orchid_extension::atom_owned::{DeserializeCtx, OwnedAtom, OwnedVariant};
|
||||||
use orchid_extension::expr::Expr;
|
use orchid_extension::expr::Expr;
|
||||||
|
use orchid_extension::gen_expr::sym_ref;
|
||||||
|
|
||||||
use crate::api;
|
use crate::api;
|
||||||
|
use crate::std::protocol::types::{GetImplMethod, GetTagIdMethod};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Record(pub Rc<HashMap<IStr, Expr>>);
|
pub struct Record(pub Rc<HashMap<IStr, Expr>>);
|
||||||
@@ -35,3 +39,21 @@ impl OwnedAtom for Record {
|
|||||||
|
|
||||||
async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) }
|
async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) }
|
||||||
}
|
}
|
||||||
|
impl Supports<GetTagIdMethod> for Record {
|
||||||
|
async fn handle(&self, _: GetTagIdMethod) -> <GetTagIdMethod as Request>::Response {
|
||||||
|
Sym::literal("std::record::Record").await.to_api()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Supports<GetImplMethod> for Record {
|
||||||
|
async fn handle(&self, req: GetImplMethod) -> <GetImplMethod as Request>::Response {
|
||||||
|
let name = Sym::from_api(req.0).await;
|
||||||
|
let val = if name == sym!(std::ops::get) {
|
||||||
|
sym_ref(sym!(std::record::get))
|
||||||
|
} else if name == sym!(std::ops::set) {
|
||||||
|
sym_ref(sym!(std::record::set))
|
||||||
|
} else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
Some(val.create().await.serialize().await)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -18,21 +18,23 @@ use super::number::num_lib::gen_num_lib;
|
|||||||
use super::string::str_atom::{IntStrAtom, StrAtom};
|
use super::string::str_atom::{IntStrAtom, StrAtom};
|
||||||
use super::string::str_lib::gen_str_lib;
|
use super::string::str_lib::gen_str_lib;
|
||||||
use crate::std::number::num_lexer::NumLexer;
|
use crate::std::number::num_lexer::NumLexer;
|
||||||
|
use crate::std::ops::gen_ops_lib;
|
||||||
use crate::std::option::{OptAtom, gen_option_lib};
|
use crate::std::option::{OptAtom, gen_option_lib};
|
||||||
use crate::std::protocol::proto_parser::{AsProtoParser, ProtoParser};
|
use crate::std::protocol::proto_parser::{AsProtoParser, ProtoParser};
|
||||||
use crate::std::protocol::type_parser::{AsTypeParser, TypeParser};
|
use crate::std::protocol::type_parser::{AsTypeParser, TypeParser};
|
||||||
use crate::std::protocol::types::{Tag, Tagged, gen_protocol_lib};
|
use crate::std::protocol::types::{CreateTag, Tag, Tagged, gen_protocol_lib};
|
||||||
use crate::std::record::record_atom::Record;
|
use crate::std::record::record_atom::Record;
|
||||||
use crate::std::record::record_lib::gen_record_lib;
|
use crate::std::record::record_lib::gen_record_lib;
|
||||||
use crate::std::reflection::sym_atom::{CreateSymAtom, SymAtom, gen_sym_lib};
|
use crate::std::reflection::sym_atom::{CreateSymAtom, SymAtom, gen_sym_lib};
|
||||||
use crate::std::string::str_lexer::StringLexer;
|
use crate::std::string::str_lexer::StringLexer;
|
||||||
use crate::std::string::to_string::AsStrTag;
|
|
||||||
use crate::std::tuple::{CreateTuple, Tuple, TupleBuilder, gen_tuple_lib};
|
use crate::std::tuple::{CreateTuple, Tuple, TupleBuilder, gen_tuple_lib};
|
||||||
use crate::{Float, Int};
|
use crate::{Float, Int};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Coding, Hierarchy)]
|
#[derive(Clone, Debug, Coding, Hierarchy)]
|
||||||
#[extendable]
|
#[extendable]
|
||||||
|
#[allow(clippy::enum_variant_names, reason = "For the time being there are only ctor calls")]
|
||||||
pub enum StdReq {
|
pub enum StdReq {
|
||||||
|
CreateTag(CreateTag),
|
||||||
CreateTuple(CreateTuple),
|
CreateTuple(CreateTuple),
|
||||||
CreateSymAtom(CreateSymAtom),
|
CreateSymAtom(CreateSymAtom),
|
||||||
}
|
}
|
||||||
@@ -61,7 +63,6 @@ impl SystemCard for StdSystem {
|
|||||||
Some(TupleBuilder::dynfo()),
|
Some(TupleBuilder::dynfo()),
|
||||||
Some(Tag::dynfo()),
|
Some(Tag::dynfo()),
|
||||||
Some(Tagged::dynfo()),
|
Some(Tagged::dynfo()),
|
||||||
Some(AsStrTag::dynfo()),
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -77,6 +78,21 @@ impl System for StdSystem {
|
|||||||
let sym_atom = SymAtom(Sym::from_api(sym_tok).await);
|
let sym_atom = SymAtom(Sym::from_api(sym_tok).await);
|
||||||
xreq.reply(req, &sym_atom.to_expr().await.serialize().await).await.unwrap()
|
xreq.reply(req, &sym_atom.to_expr().await.serialize().await).await.unwrap()
|
||||||
},
|
},
|
||||||
|
StdReq::CreateTag(ref req @ CreateTag { name, ref impls }) => {
|
||||||
|
let tag_atom = Tag {
|
||||||
|
id: Sym::from_api(name).await,
|
||||||
|
impls: Rc::new(
|
||||||
|
join_all(
|
||||||
|
(impls.iter())
|
||||||
|
.map(|(k, v)| async { (Sym::from_api(*k).await, Expr::deserialize(*v).await) }),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
xreq.reply(req, &tag_atom.to_expr().await.serialize().await).await.unwrap()
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn lexers() -> Vec<LexerObj> { vec![&StringLexer, &NumLexer] }
|
fn lexers() -> Vec<LexerObj> { vec![&StringLexer, &NumLexer] }
|
||||||
@@ -90,6 +106,7 @@ impl System for StdSystem {
|
|||||||
gen_tuple_lib(),
|
gen_tuple_lib(),
|
||||||
gen_protocol_lib(),
|
gen_protocol_lib(),
|
||||||
gen_sym_lib().await,
|
gen_sym_lib().await,
|
||||||
|
gen_ops_lib(),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
async fn prelude() -> Vec<Sym> { vec![sym!(std), sym!(std::tuple), sym!(std::option)] }
|
async fn prelude() -> Vec<Sym> { vec![sym!(std), sym!(std::tuple), sym!(std::option)] }
|
||||||
|
|||||||
@@ -9,36 +9,34 @@ use orchid_api_traits::{Encode, Request};
|
|||||||
use orchid_base::error::{OrcRes, mk_errv};
|
use orchid_base::error::{OrcRes, mk_errv};
|
||||||
use orchid_base::format::{FmtCtx, FmtUnit};
|
use orchid_base::format::{FmtCtx, FmtUnit};
|
||||||
use orchid_base::interner::{IStr, es, is};
|
use orchid_base::interner::{IStr, es, is};
|
||||||
|
use orchid_base::name::Sym;
|
||||||
|
use orchid_base::sym;
|
||||||
use orchid_extension::atom::{AtomMethod, Atomic, MethodSetBuilder, Supports, TAtom};
|
use orchid_extension::atom::{AtomMethod, Atomic, MethodSetBuilder, Supports, TAtom};
|
||||||
use orchid_extension::atom_owned::{DeserializeCtx, OwnedAtom, OwnedVariant};
|
use orchid_extension::atom_owned::{DeserializeCtx, OwnedAtom, OwnedVariant};
|
||||||
use orchid_extension::conv::TryFromExpr;
|
use orchid_extension::conv::TryFromExpr;
|
||||||
use orchid_extension::expr::Expr;
|
use orchid_extension::expr::Expr;
|
||||||
|
use orchid_extension::gen_expr::sym_ref;
|
||||||
|
|
||||||
|
use crate::std::protocol::types::{GetImplMethod, GetTagIdMethod};
|
||||||
use crate::std::string::to_string::ToStringMethod;
|
use crate::std::string::to_string::ToStringMethod;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Coding)]
|
#[derive(Copy, Clone, Debug, Coding)]
|
||||||
pub struct StringGetVal;
|
pub struct StringGetValMethod;
|
||||||
impl Request for StringGetVal {
|
impl Request for StringGetValMethod {
|
||||||
type Response = Rc<String>;
|
type Response = Rc<String>;
|
||||||
}
|
}
|
||||||
impl AtomMethod for StringGetVal {
|
impl AtomMethod for StringGetValMethod {
|
||||||
const NAME: &str = "std::string_get_val";
|
const NAME: &str = "std::string_get_val";
|
||||||
}
|
}
|
||||||
impl Supports<StringGetVal> for StrAtom {
|
|
||||||
async fn handle(&self, _: StringGetVal) -> <StringGetVal as Request>::Response { self.0.clone() }
|
|
||||||
}
|
|
||||||
impl Supports<ToStringMethod> for StrAtom {
|
|
||||||
async fn handle(&self, _: ToStringMethod) -> <ToStringMethod as Request>::Response {
|
|
||||||
self.0.as_str().to_string()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct StrAtom(Rc<String>);
|
pub struct StrAtom(Rc<String>);
|
||||||
impl Atomic for StrAtom {
|
impl Atomic for StrAtom {
|
||||||
type Variant = OwnedVariant;
|
type Variant = OwnedVariant;
|
||||||
type Data = ();
|
type Data = ();
|
||||||
fn reg_reqs() -> MethodSetBuilder<Self> { MethodSetBuilder::new().handle::<StringGetVal>() }
|
fn reg_reqs() -> MethodSetBuilder<Self> {
|
||||||
|
MethodSetBuilder::new().handle::<StringGetValMethod>().handle::<ToStringMethod>()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
impl StrAtom {
|
impl StrAtom {
|
||||||
pub fn new(str: Rc<String>) -> Self { Self(str) }
|
pub fn new(str: Rc<String>) -> Self { Self(str) }
|
||||||
@@ -60,12 +58,44 @@ impl OwnedAtom for StrAtom {
|
|||||||
Self::new(Rc::new(ctx.read::<String>().await))
|
Self::new(Rc::new(ctx.read::<String>().await))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl Supports<StringGetValMethod> for StrAtom {
|
||||||
|
async fn handle(&self, _: StringGetValMethod) -> <StringGetValMethod as Request>::Response {
|
||||||
|
self.0.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Supports<ToStringMethod> for StrAtom {
|
||||||
|
async fn handle(&self, _: ToStringMethod) -> <ToStringMethod as Request>::Response {
|
||||||
|
self.0.as_str().to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Supports<GetTagIdMethod> for StrAtom {
|
||||||
|
async fn handle(&self, _: GetTagIdMethod) -> <GetTagIdMethod as Request>::Response {
|
||||||
|
Sym::literal("std::string::StrAtom").await.to_api()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Supports<GetImplMethod> for StrAtom {
|
||||||
|
async fn handle(&self, req: GetImplMethod) -> <GetImplMethod as Request>::Response {
|
||||||
|
let name = Sym::from_api(req.0).await;
|
||||||
|
let val = if name == sym!(std::ops::add) {
|
||||||
|
sym_ref(sym!(std::string::concat))
|
||||||
|
} else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
Some(val.create().await.serialize().await)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct IntStrAtom(pub(crate) IStr);
|
pub struct IntStrAtom(pub(crate) IStr);
|
||||||
impl Atomic for IntStrAtom {
|
impl Atomic for IntStrAtom {
|
||||||
type Variant = OwnedVariant;
|
type Variant = OwnedVariant;
|
||||||
type Data = orchid_api::TStr;
|
type Data = orchid_api::TStr;
|
||||||
|
fn reg_reqs() -> MethodSetBuilder<Self> {
|
||||||
|
MethodSetBuilder::new()
|
||||||
|
.handle::<GetTagIdMethod>()
|
||||||
|
.handle::<GetImplMethod>()
|
||||||
|
.handle::<ToStringMethod>()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
impl From<IStr> for IntStrAtom {
|
impl From<IStr> for IntStrAtom {
|
||||||
fn from(value: IStr) -> Self { Self(value) }
|
fn from(value: IStr) -> Self { Self(value) }
|
||||||
@@ -94,6 +124,22 @@ impl Supports<ToStringMethod> for IntStrAtom {
|
|||||||
self.0.to_string()
|
self.0.to_string()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl Supports<GetTagIdMethod> for IntStrAtom {
|
||||||
|
async fn handle(&self, _: GetTagIdMethod) -> <GetTagIdMethod as Request>::Response {
|
||||||
|
Sym::literal("std::string::IntStrAtom").await.to_api()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Supports<GetImplMethod> for IntStrAtom {
|
||||||
|
async fn handle(&self, req: GetImplMethod) -> <GetImplMethod as Request>::Response {
|
||||||
|
let name = Sym::from_api(req.0).await;
|
||||||
|
let val = if name == sym!(std::ops::add) {
|
||||||
|
sym_ref(sym!(std::string::concat))
|
||||||
|
} else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
Some(val.create().await.serialize().await)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct OrcString {
|
pub struct OrcString {
|
||||||
@@ -109,7 +155,7 @@ impl OrcString {
|
|||||||
pub async fn get_string(&self) -> Rc<String> {
|
pub async fn get_string(&self) -> Rc<String> {
|
||||||
match &self.kind {
|
match &self.kind {
|
||||||
OrcStringKind::Int(tok) => es(**tok).await.rc(),
|
OrcStringKind::Int(tok) => es(**tok).await.rc(),
|
||||||
OrcStringKind::Val(atom) => atom.request(StringGetVal).await,
|
OrcStringKind::Val(atom) => atom.request(StringGetValMethod).await,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,12 +7,12 @@ use orchid_extension::conv::ToExpr;
|
|||||||
use orchid_extension::coroutine_exec::exec;
|
use orchid_extension::coroutine_exec::exec;
|
||||||
use orchid_extension::expr::Expr;
|
use orchid_extension::expr::Expr;
|
||||||
use orchid_extension::gen_expr::{call, sym_ref};
|
use orchid_extension::gen_expr::{call, sym_ref};
|
||||||
use orchid_extension::tree::{GenMember, cnst, comments, fun, prefix};
|
use orchid_extension::tree::{GenMember, comments, fun, prefix};
|
||||||
|
|
||||||
use super::str_atom::StrAtom;
|
use super::str_atom::StrAtom;
|
||||||
use crate::OrcString;
|
use crate::OrcString;
|
||||||
use crate::std::protocol::types::get_impl;
|
use crate::std::protocol::types::{get_impl, proto};
|
||||||
use crate::std::string::to_string::{AsStrTag, ToStringMethod};
|
use crate::std::string::to_string::ToStringMethod;
|
||||||
|
|
||||||
pub fn gen_str_lib() -> Vec<GenMember> {
|
pub fn gen_str_lib() -> Vec<GenMember> {
|
||||||
prefix("std::string", [
|
prefix("std::string", [
|
||||||
@@ -45,15 +45,6 @@ pub fn gen_str_lib() -> Vec<GenMember> {
|
|||||||
.await
|
.await
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
prefix("to_string", [
|
proto(true, "to_string").finish(),
|
||||||
cnst(true, "__type_tag__", AsStrTag),
|
|
||||||
fun(true, "resolve", async |atom: ForeignAtom| {
|
|
||||||
exec(async |mut h| {
|
|
||||||
let proto = h.exec(sym_ref(sym!(std::string::to_string))).await?;
|
|
||||||
Ok(call(get_impl(atom.clone(), proto).await?.to_gen().await, [atom.to_gen().await]))
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
}),
|
|
||||||
]),
|
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,30 +1,8 @@
|
|||||||
use orchid_api_derive::Coding;
|
use orchid_api_derive::Coding;
|
||||||
use orchid_api_traits::Request;
|
use orchid_api_traits::Request;
|
||||||
use orchid_base::name::Sym;
|
use orchid_extension::atom::AtomMethod;
|
||||||
use orchid_extension::atom::{AtomMethod, Atomic, MethodSetBuilder, Supports};
|
|
||||||
use orchid_extension::atom_thin::{ThinAtom, ThinVariant};
|
|
||||||
|
|
||||||
use crate::std::protocol::types::{GetImplMethod, GetTagIdMethod};
|
|
||||||
|
|
||||||
#[derive(Coding, Clone, Debug)]
|
|
||||||
pub struct AsStrTag;
|
|
||||||
impl Atomic for AsStrTag {
|
|
||||||
type Data = AsStrTag;
|
|
||||||
type Variant = ThinVariant;
|
|
||||||
fn reg_reqs() -> MethodSetBuilder<Self> {
|
|
||||||
MethodSetBuilder::new().handle::<GetTagIdMethod>().handle::<GetImplMethod>()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl ThinAtom for AsStrTag {}
|
|
||||||
impl Supports<GetTagIdMethod> for AsStrTag {
|
|
||||||
async fn handle(&self, _: GetTagIdMethod) -> <GetTagIdMethod as Request>::Response {
|
|
||||||
Sym::parse("std::string::to_string").await.unwrap().to_api()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Supports<GetImplMethod> for AsStrTag {
|
|
||||||
async fn handle(&self, _: GetImplMethod) -> <GetImplMethod as Request>::Response { None }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/// Method version of std::string::to_string protocol for atoms
|
||||||
#[derive(Coding, Clone, Debug)]
|
#[derive(Coding, Clone, Debug)]
|
||||||
pub struct ToStringMethod;
|
pub struct ToStringMethod;
|
||||||
impl Request for ToStringMethod {
|
impl Request for ToStringMethod {
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ impl Spawner for SpawnerImpl {
|
|||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> io::Result<ExitCode> {
|
async fn main() -> io::Result<ExitCode> {
|
||||||
eprintln!("Orcx was made by Lawrence Bethlenfalvy");
|
eprintln!("Orcx v0.1 is free software provided without warranty.");
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
let exit_code = Rc::new(RefCell::new(ExitCode::SUCCESS));
|
let exit_code = Rc::new(RefCell::new(ExitCode::SUCCESS));
|
||||||
let local_set = LocalSet::new();
|
let local_set = LocalSet::new();
|
||||||
@@ -424,8 +424,9 @@ async fn main() -> io::Result<ExitCode> {
|
|||||||
xctx.set_gas(Some(10_000));
|
xctx.set_gas(Some(10_000));
|
||||||
xctx.execute().await;
|
xctx.execute().await;
|
||||||
match xctx.result() {
|
match xctx.result() {
|
||||||
ExecResult::Value(val) =>
|
ExecResult::Value(val) => {
|
||||||
println!("{}", take_first(&val.print(&FmtCtxImpl::default()).await, false)),
|
println!("{}", take_first(&val.print(&FmtCtxImpl::default()).await, false))
|
||||||
|
},
|
||||||
ExecResult::Err(e) => println!("error: {e}"),
|
ExecResult::Err(e) => println!("error: {e}"),
|
||||||
ExecResult::Gas(_) => println!("Ran out of gas!"),
|
ExecResult::Gas(_) => println!("Ran out of gas!"),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ pub struct Args {
|
|||||||
pub enum Commands {
|
pub enum Commands {
|
||||||
CheckApiRefs,
|
CheckApiRefs,
|
||||||
Orcx {
|
Orcx {
|
||||||
|
#[arg(long)]
|
||||||
|
release: bool,
|
||||||
#[arg(trailing_var_arg = true, num_args = 1..)]
|
#[arg(trailing_var_arg = true, num_args = 1..)]
|
||||||
argv: Vec<String>,
|
argv: Vec<String>,
|
||||||
},
|
},
|
||||||
@@ -41,7 +43,7 @@ fn main() -> io::Result<ExitCode> {
|
|||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
match &args.command {
|
match &args.command {
|
||||||
Commands::CheckApiRefs => check_api_refs(&args)?,
|
Commands::CheckApiRefs => check_api_refs(&args)?,
|
||||||
Commands::Orcx { argv } => orcx(&args, argv)?,
|
Commands::Orcx { release, argv } => orcx(*release, &args, argv)?,
|
||||||
Commands::Orcxdb { argv } => orcxdb(&args, argv)?,
|
Commands::Orcxdb { argv } => orcxdb(&args, argv)?,
|
||||||
}
|
}
|
||||||
Ok(if EXIT_OK.load(Ordering::Relaxed) { ExitCode::SUCCESS } else { ExitCode::FAILURE })
|
Ok(if EXIT_OK.load(Ordering::Relaxed) { ExitCode::SUCCESS } else { ExitCode::FAILURE })
|
||||||
|
|||||||
@@ -4,17 +4,25 @@ use std::sync::atomic::Ordering;
|
|||||||
|
|
||||||
use crate::{Args, EXIT_OK};
|
use crate::{Args, EXIT_OK};
|
||||||
|
|
||||||
pub fn orcx(_args: &Args, argv: &[String]) -> io::Result<()> {
|
pub fn orcx(release: bool, _args: &Args, argv: &[String]) -> io::Result<()> {
|
||||||
if !Command::new("cargo").args(["build", "-p", "orchid-std", "--quiet"]).status()?.success() {
|
let mut std_build_cmd = Command::new("cargo");
|
||||||
|
std_build_cmd.args(["build", "-p", "orchid-std", "--quiet"]);
|
||||||
|
if release {
|
||||||
|
std_build_cmd.arg("--release");
|
||||||
|
}
|
||||||
|
|
||||||
|
if !std_build_cmd.status()?.success() {
|
||||||
EXIT_OK.store(false, Ordering::Relaxed);
|
EXIT_OK.store(false, Ordering::Relaxed);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
if !Command::new("cargo")
|
let mut run_cmd = Command::new("cargo");
|
||||||
.args(["run", "-p", "orcx", "--quiet", "--"])
|
run_cmd.args(["run", "-p", "orcx", "--quiet"]);
|
||||||
.args(argv)
|
if release {
|
||||||
.status()?
|
run_cmd.arg("--release");
|
||||||
.success()
|
}
|
||||||
{
|
run_cmd.arg("--");
|
||||||
|
run_cmd.args(argv);
|
||||||
|
if !run_cmd.status()?.success() {
|
||||||
EXIT_OK.store(false, Ordering::Relaxed);
|
EXIT_OK.store(false, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
Reference in New Issue
Block a user