Protocols and operators mostly
All checks were successful
Rust / build (push) Successful in 4m8s

This commit is contained in:
2026-01-21 22:22:58 +01:00
parent 75b05a2965
commit f38193edcc
33 changed files with 578 additions and 147 deletions

View File

@@ -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;

View File

@@ -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", ","])

View File

@@ -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()),
})

View File

@@ -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(),
])
])
}

View File

@@ -1,4 +1,5 @@
pub mod number;
pub mod ops;
pub mod option;
pub mod protocol;
pub mod record;

View File

@@ -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()

View File

@@ -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())),
])
}

View 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(),
),
])
}

View File

@@ -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;

View File

@@ -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
}
}

View File

@@ -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)
}
}

View File

@@ -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)] }

View File

@@ -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,
}
}
}

View File

@@ -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(),
])
}

View File

@@ -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 {