This commit is contained in:
@@ -3,6 +3,7 @@ mod std;
|
||||
|
||||
pub use std::number::num_atom::{Float, HomoArray, Int, Num};
|
||||
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::std_system::StdSystem;
|
||||
pub use std::string::str_atom::OrcString;
|
||||
|
||||
@@ -14,17 +14,36 @@ use crate::{HomoTpl, UntypedTuple};
|
||||
pub async fn gen_macro_lib() -> Vec<GenMember> {
|
||||
prefix("macros", [
|
||||
fun(true, "resolve", async |tpl: TAtom<MacTree>| resolve(own(&tpl).await).await),
|
||||
// TODO test whether any of this worked
|
||||
prefix("common", [
|
||||
build_macro(None, ["..", "_"]).finish(),
|
||||
build_macro(Some(1), ["+"])
|
||||
.rule(mactreev!("...$" lhs 0 macros::common::+ "...$" rhs 1), [async |[lhs, rhs]| {
|
||||
call(sym_ref(sym!(std::number::add)), [resolve(lhs).await, resolve(rhs).await])
|
||||
.rule(mactreev!("...$" lhs 1 macros::common::+ "...$" rhs 0), [async |[lhs, rhs]| {
|
||||
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(),
|
||||
build_macro(Some(2), ["*"])
|
||||
.rule(mactreev!("...$" lhs 0 macros::common::* "...$" rhs 1), [async |[lhs, rhs]| {
|
||||
call(sym_ref(sym!(std::number::mul)), [resolve(lhs).await, resolve(rhs).await])
|
||||
.rule(mactreev!("...$" lhs 1 macros::common::* "...$" rhs 0), [async |[lhs, rhs]| {
|
||||
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(),
|
||||
build_macro(None, ["comma_list", ","])
|
||||
|
||||
@@ -123,12 +123,13 @@ async fn mk_scalar(pattern: &MacTree) -> OrcRes<ScalMatcher> {
|
||||
PhKind::Scalar => ScalMatcher::Placeh { key: name.clone() },
|
||||
},
|
||||
MacTok::S(c, body) => ScalMatcher::S(*c, Box::new(mk_any(&body.items).boxed_local().await?)),
|
||||
MacTok::Lambda(..) =>
|
||||
MacTok::Lambda(..) => {
|
||||
return Err(mk_errv(
|
||||
is("Lambda in matcher").await,
|
||||
"Lambdas can't be matched for, only generated in templates",
|
||||
[pattern.pos()],
|
||||
)),
|
||||
));
|
||||
},
|
||||
MacTok::Value(_) | MacTok::Slot => panic!("Only used for templating"),
|
||||
MacTok::Bottom(errv) => return Err(errv.clone()),
|
||||
})
|
||||
|
||||
@@ -95,6 +95,30 @@ pub async fn gen_std_macro_lib() -> Vec<GenMember> {
|
||||
.finish(),
|
||||
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 ops;
|
||||
pub mod option;
|
||||
pub mod protocol;
|
||||
pub mod record;
|
||||
|
||||
@@ -4,14 +4,18 @@ use orchid_base::error::OrcRes;
|
||||
use orchid_base::format::FmtUnit;
|
||||
use orchid_base::name::Sym;
|
||||
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::conv::TryFromExpr;
|
||||
use orchid_extension::expr::Expr;
|
||||
use orchid_extension::gen_expr::sym_ref;
|
||||
use ordered_float::NotNan;
|
||||
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;
|
||||
|
||||
#[derive(Clone, Debug, Coding)]
|
||||
@@ -19,6 +23,12 @@ pub struct Int(pub i64);
|
||||
impl Atomic for Int {
|
||||
type Variant = ThinVariant;
|
||||
type Data = Self;
|
||||
fn reg_reqs() -> MethodSetBuilder<Self> {
|
||||
MethodSetBuilder::new()
|
||||
.handle::<GetTagIdMethod>()
|
||||
.handle::<GetImplMethod>()
|
||||
.handle::<ToStringMethod>()
|
||||
}
|
||||
}
|
||||
impl ThinAtom for Int {
|
||||
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()
|
||||
}
|
||||
}
|
||||
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 {
|
||||
async fn handle(&self, _: ToStringMethod) -> <ToStringMethod as Request>::Response {
|
||||
self.0.to_string()
|
||||
@@ -44,6 +73,12 @@ pub struct Float(pub NotNan<f64>);
|
||||
impl Atomic for Float {
|
||||
type Variant = ThinVariant;
|
||||
type Data = Self;
|
||||
fn reg_reqs() -> MethodSetBuilder<Self> {
|
||||
MethodSetBuilder::new()
|
||||
.handle::<GetTagIdMethod>()
|
||||
.handle::<GetImplMethod>()
|
||||
.handle::<ToStringMethod>()
|
||||
}
|
||||
}
|
||||
impl ThinAtom for Float {
|
||||
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()))
|
||||
}
|
||||
}
|
||||
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 {
|
||||
async fn handle(&self, _: ToStringMethod) -> <ToStringMethod as Request>::Response {
|
||||
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_extension::func_atom::get_arg;
|
||||
use orchid_extension::tree::{GenMember, fun, prefix};
|
||||
use ordered_float::NotNan;
|
||||
use rust_decimal::prelude::ToPrimitive;
|
||||
|
||||
use super::num_atom::{Float, HomoArray, Int, Num};
|
||||
|
||||
pub fn gen_num_lib() -> Vec<GenMember> {
|
||||
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]) {
|
||||
HomoArray::Int([a, b]) => Numeric::Int(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 {
|
||||
Numeric::Int(i) => Numeric::Int(-i),
|
||||
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]) {
|
||||
HomoArray::Int([a, b]) => Numeric::Int(a * b),
|
||||
HomoArray::Float([a, b]) => Numeric::Float(a * b),
|
||||
})
|
||||
}),
|
||||
fun(true, "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(true, "fdiv", async |a: Float, b: Float| Float(a.0 / b.0)),
|
||||
fun(true, "fmod", async |a: Float, b: Float| {
|
||||
fun(false, "idiv", async |a: Int, b: Int| Int(a.0 / b.0)),
|
||||
fun(false, "imod", async |a: Int, b: Int| Int(a.0 % b.0)),
|
||||
fun(false, "fdiv", async |a: Float, b: Float| Float(a.0 / b.0)),
|
||||
fun(false, "fmod", async |a: Float, b: Float| {
|
||||
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<()> {
|
||||
let body = match &body_tt.tok {
|
||||
Token::S(Paren::Round, body) => line_items(Snippet::new(body_tt, body)).await,
|
||||
Token::S(ptyp, _) =>
|
||||
Token::S(ptyp, _) => {
|
||||
return Err(mk_errv(
|
||||
is("Incorrect paren type").await,
|
||||
format!("Expected () block, found {ptyp}"),
|
||||
[body_tt.sr().pos()],
|
||||
)),
|
||||
_ =>
|
||||
));
|
||||
},
|
||||
_ => {
|
||||
return Err(
|
||||
token_errv(body_tt, "Expected body", |s| format!("Expected (impl ...) block, found {s}"))
|
||||
.await,
|
||||
),
|
||||
);
|
||||
},
|
||||
};
|
||||
for Parsed { tail: line, output: comments } in body {
|
||||
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(Some(ref n @ Import { name: Some(_), ref sr, .. })) =>
|
||||
(n.clone().mspath().to_sym().await, sr.clone()),
|
||||
Ok(Some(Import { name: None, sr, .. })) =>
|
||||
Ok(Some(Import { name: None, sr, .. })) => {
|
||||
return Err(mk_errv(
|
||||
is("impl line with globstar").await,
|
||||
"::* is not permitted in a protocol impl",
|
||||
[sr.pos()],
|
||||
)),
|
||||
Err(e) =>
|
||||
));
|
||||
},
|
||||
Err(e) => {
|
||||
return Err(mk_errv(
|
||||
is("Impl line with multiple protocol names").await,
|
||||
"::() is not permitted in a protocol impl",
|
||||
e.map(|i| i.sr.pos()),
|
||||
)),
|
||||
));
|
||||
},
|
||||
};
|
||||
let Parsed { tail, .. } = expect_tok(tail, is("as").await).await?;
|
||||
let cnst_name = is(&format!("{}{}", lines.len(), name.iter().join("__"))).await;
|
||||
|
||||
@@ -1,22 +1,29 @@
|
||||
use std::borrow::Cow;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
use futures::FutureExt;
|
||||
use futures::future::{LocalBoxFuture, join_all};
|
||||
use hashbrown::HashMap;
|
||||
use itertools::Itertools;
|
||||
use never::Never;
|
||||
use orchid_api_derive::Coding;
|
||||
use orchid_api_derive::{Coding, Hierarchy};
|
||||
use orchid_api_traits::Request;
|
||||
use orchid_base::error::{OrcRes, mk_errv};
|
||||
use orchid_base::format::fmt;
|
||||
use orchid_base::interner::is;
|
||||
use orchid_base::name::Sym;
|
||||
use orchid_base::interner::{ev, is};
|
||||
use orchid_base::name::{NameLike, Sym, VName};
|
||||
use orchid_extension::atom::{AtomMethod, Atomic, ForeignAtom, MethodSetBuilder, Supports, TAtom};
|
||||
use orchid_extension::atom_owned::{OwnedAtom, OwnedVariant, own};
|
||||
use orchid_extension::conv::ToExpr;
|
||||
use orchid_extension::expr::Expr;
|
||||
use orchid_extension::gen_expr::call;
|
||||
use orchid_extension::tree::{GenMember, fun, prefix};
|
||||
use orchid_extension::conv::{ClonableToExprDyn, ToExpr};
|
||||
use orchid_extension::coroutine_exec::exec;
|
||||
use orchid_extension::expr::{Expr, ExprHandle};
|
||||
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)]
|
||||
pub struct Tag {
|
||||
@@ -26,17 +33,25 @@ pub struct Tag {
|
||||
impl Atomic for Tag {
|
||||
type Data = api::TStrv;
|
||||
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 {
|
||||
type Refs = Never;
|
||||
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 {
|
||||
async fn handle(&self, req: GetImplMethod) -> <GetImplMethod as Request>::Response {
|
||||
self.impls.get(&Sym::from_api(req.0).await).map(|expr| expr.handle().ticket())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Coding)]
|
||||
pub struct GetImplMethod(pub api::TStrv);
|
||||
impl Request for GetImplMethod {
|
||||
@@ -75,14 +90,16 @@ impl Supports<GetImplMethod> for Tagged {
|
||||
|
||||
pub async fn get_impl(receiver: ForeignAtom, proto: ForeignAtom) -> OrcRes<Expr> {
|
||||
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", [
|
||||
proto.pos()
|
||||
]));
|
||||
return Err(mk_errv(
|
||||
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 {
|
||||
return Err(mk_errv(
|
||||
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()],
|
||||
));
|
||||
};
|
||||
@@ -92,14 +109,14 @@ pub async fn get_impl(receiver: ForeignAtom, proto: ForeignAtom) -> OrcRes<Expr>
|
||||
let Some(type_id) = receiver.request(GetTagIdMethod).await else {
|
||||
return Err(mk_errv(
|
||||
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()],
|
||||
));
|
||||
};
|
||||
let Some(impl_val_opt) = proto.request(GetImplMethod(type_id)).await else {
|
||||
return Err(mk_errv(
|
||||
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()],
|
||||
));
|
||||
};
|
||||
@@ -108,7 +125,7 @@ pub async fn get_impl(receiver: ForeignAtom, proto: ForeignAtom) -> OrcRes<Expr>
|
||||
}
|
||||
return Err(mk_errv(
|
||||
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()],
|
||||
));
|
||||
}
|
||||
@@ -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::future::join_all;
|
||||
use hashbrown::HashMap;
|
||||
use orchid_api_traits::Encode;
|
||||
use orchid_api_traits::{Encode, Request};
|
||||
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::expr::Expr;
|
||||
use orchid_extension::gen_expr::sym_ref;
|
||||
|
||||
use crate::api;
|
||||
use crate::std::protocol::types::{GetImplMethod, GetTagIdMethod};
|
||||
|
||||
#[derive(Clone)]
|
||||
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(()) }
|
||||
}
|
||||
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_lib::gen_str_lib;
|
||||
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::protocol::proto_parser::{AsProtoParser, ProtoParser};
|
||||
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_lib::gen_record_lib;
|
||||
use crate::std::reflection::sym_atom::{CreateSymAtom, SymAtom, gen_sym_lib};
|
||||
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::{Float, Int};
|
||||
|
||||
#[derive(Clone, Debug, Coding, Hierarchy)]
|
||||
#[extendable]
|
||||
#[allow(clippy::enum_variant_names, reason = "For the time being there are only ctor calls")]
|
||||
pub enum StdReq {
|
||||
CreateTag(CreateTag),
|
||||
CreateTuple(CreateTuple),
|
||||
CreateSymAtom(CreateSymAtom),
|
||||
}
|
||||
@@ -61,7 +63,6 @@ impl SystemCard for StdSystem {
|
||||
Some(TupleBuilder::dynfo()),
|
||||
Some(Tag::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);
|
||||
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] }
|
||||
@@ -90,6 +106,7 @@ impl System for StdSystem {
|
||||
gen_tuple_lib(),
|
||||
gen_protocol_lib(),
|
||||
gen_sym_lib().await,
|
||||
gen_ops_lib(),
|
||||
])
|
||||
}
|
||||
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::format::{FmtCtx, FmtUnit};
|
||||
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_owned::{DeserializeCtx, OwnedAtom, OwnedVariant};
|
||||
use orchid_extension::conv::TryFromExpr;
|
||||
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;
|
||||
|
||||
#[derive(Copy, Clone, Debug, Coding)]
|
||||
pub struct StringGetVal;
|
||||
impl Request for StringGetVal {
|
||||
pub struct StringGetValMethod;
|
||||
impl Request for StringGetValMethod {
|
||||
type Response = Rc<String>;
|
||||
}
|
||||
impl AtomMethod for StringGetVal {
|
||||
impl AtomMethod for StringGetValMethod {
|
||||
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)]
|
||||
pub struct StrAtom(Rc<String>);
|
||||
impl Atomic for StrAtom {
|
||||
type Variant = OwnedVariant;
|
||||
type Data = ();
|
||||
fn reg_reqs() -> MethodSetBuilder<Self> { MethodSetBuilder::new().handle::<StringGetVal>() }
|
||||
fn reg_reqs() -> MethodSetBuilder<Self> {
|
||||
MethodSetBuilder::new().handle::<StringGetValMethod>().handle::<ToStringMethod>()
|
||||
}
|
||||
}
|
||||
impl StrAtom {
|
||||
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))
|
||||
}
|
||||
}
|
||||
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)]
|
||||
pub struct IntStrAtom(pub(crate) IStr);
|
||||
impl Atomic for IntStrAtom {
|
||||
type Variant = OwnedVariant;
|
||||
type Data = orchid_api::TStr;
|
||||
fn reg_reqs() -> MethodSetBuilder<Self> {
|
||||
MethodSetBuilder::new()
|
||||
.handle::<GetTagIdMethod>()
|
||||
.handle::<GetImplMethod>()
|
||||
.handle::<ToStringMethod>()
|
||||
}
|
||||
}
|
||||
impl From<IStr> for IntStrAtom {
|
||||
fn from(value: IStr) -> Self { Self(value) }
|
||||
@@ -94,6 +124,22 @@ impl Supports<ToStringMethod> for IntStrAtom {
|
||||
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)]
|
||||
pub struct OrcString {
|
||||
@@ -109,7 +155,7 @@ impl OrcString {
|
||||
pub async fn get_string(&self) -> Rc<String> {
|
||||
match &self.kind {
|
||||
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::expr::Expr;
|
||||
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 crate::OrcString;
|
||||
use crate::std::protocol::types::get_impl;
|
||||
use crate::std::string::to_string::{AsStrTag, ToStringMethod};
|
||||
use crate::std::protocol::types::{get_impl, proto};
|
||||
use crate::std::string::to_string::ToStringMethod;
|
||||
|
||||
pub fn gen_str_lib() -> Vec<GenMember> {
|
||||
prefix("std::string", [
|
||||
@@ -45,15 +45,6 @@ pub fn gen_str_lib() -> Vec<GenMember> {
|
||||
.await
|
||||
}),
|
||||
),
|
||||
prefix("to_string", [
|
||||
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
|
||||
}),
|
||||
]),
|
||||
proto(true, "to_string").finish(),
|
||||
])
|
||||
}
|
||||
|
||||
@@ -1,30 +1,8 @@
|
||||
use orchid_api_derive::Coding;
|
||||
use orchid_api_traits::Request;
|
||||
use orchid_base::name::Sym;
|
||||
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 }
|
||||
}
|
||||
use orchid_extension::atom::AtomMethod;
|
||||
|
||||
/// Method version of std::string::to_string protocol for atoms
|
||||
#[derive(Coding, Clone, Debug)]
|
||||
pub struct ToStringMethod;
|
||||
impl Request for ToStringMethod {
|
||||
|
||||
Reference in New Issue
Block a user