Files
orchid/orchid-extension/src/gen_expr.rs
Lawrence Bethlenfalvy 534f08b45c
Some checks failed
Rust / build (push) Has been cancelled
Significantly extended stdlib
2026-01-27 20:53:45 +01:00

134 lines
4.2 KiB
Rust

use std::mem;
use std::rc::Rc;
use futures::FutureExt;
use orchid_base::error::{OrcErr, OrcErrv};
use orchid_base::format::{FmtCtx, FmtUnit, Format, Variants};
use orchid_base::location::Pos;
use orchid_base::name::Sym;
use orchid_base::{match_mapping, tl_cache};
use crate::api;
use crate::atom::{AtomFactory, ToAtom};
use crate::entrypoint::request;
use crate::expr::Expr;
#[derive(Clone, Debug)]
pub struct GExpr {
pub kind: GExprKind,
pub pos: Pos,
}
impl GExpr {
/// Release notifications will not be sent for the slots. Use this with
/// messages that imply ownership transfer
pub async fn serialize(self) -> api::Expression {
if let GExprKind::Slot(ex) = self.kind {
let hand = ex.handle();
mem::drop(ex);
api::Expression {
location: api::Location::SlotTarget,
// an instance is leaked here, we must take ownership of it when we receive this
kind: api::ExpressionKind::Slot(hand.serialize().await),
}
} else {
api::Expression {
location: api::Location::Inherit,
kind: self.kind.serialize().boxed_local().await,
}
}
}
pub fn at(self, pos: Pos) -> Self { GExpr { pos, kind: self.kind } }
pub async fn create(self) -> Expr {
Expr::deserialize(request(api::Create(self.serialize().await)).await).await
}
}
impl Format for GExpr {
async fn print<'a>(&'a self, c: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit {
self.kind.print(c).boxed_local().await
}
}
#[derive(Clone, Debug)]
pub enum GExprKind {
Call(Box<GExpr>, Box<GExpr>),
Lambda(u64, Box<GExpr>),
Arg(u64),
Seq(Box<GExpr>, Box<GExpr>),
Const(Sym),
NewAtom(AtomFactory),
Slot(Expr),
Bottom(OrcErrv),
}
impl GExprKind {
pub async fn serialize(self) -> api::ExpressionKind {
match_mapping!(self, Self => api::ExpressionKind {
Call(
f => Box::new(f.serialize().await),
x => Box::new(x.serialize().await)
),
Seq(
a => Box::new(a.serialize().await),
b => Box::new(b.serialize().await)
),
Lambda(arg, body => Box::new(body.serialize().await)),
Arg(arg),
Const(name.to_api()),
Bottom(err.to_api()),
NewAtom(fac.clone().build().await),
} {
Self::Slot(_) => panic!("processed elsewhere")
})
}
}
impl Format for GExprKind {
async fn print<'a>(&'a self, c: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit {
match self {
GExprKind::Call(f, x) =>
tl_cache!(Rc<Variants>: Rc::new(Variants::default().bounded("{0} ({1})")))
.units([f.print(c).await, x.print(c).await]),
GExprKind::Lambda(arg, body) =>
tl_cache!(Rc<Variants>: Rc::new(Variants::default().bounded("\\{0}.{1}")))
.units([arg.to_string().into(), body.print(c).await]),
GExprKind::Arg(arg) => arg.to_string().into(),
GExprKind::Seq(a, b) =>
tl_cache!(Rc<Variants>: Rc::new(Variants::default().bounded("[{0}] {1}")))
.units([a.print(c).await, b.print(c).await]),
GExprKind::Const(sym) => sym.to_string().into(),
GExprKind::NewAtom(atom_factory) => atom_factory.to_string().into(),
GExprKind::Slot(expr) =>
tl_cache!(Rc<Variants>: Rc::new(Variants::default().bounded("{{{0}}}")))
.units([expr.print(c).await]),
GExprKind::Bottom(orc_errv) => orc_errv.to_string().into(),
}
}
}
fn inherit(kind: GExprKind) -> GExpr { GExpr { pos: Pos::Inherit, kind } }
pub fn sym_ref(path: Sym) -> GExpr { inherit(GExprKind::Const(path)) }
/// Creates an expression from a new atom that we own.
pub fn new_atom<A: ToAtom>(atom: A) -> GExpr { inherit(GExprKind::NewAtom(atom.to_atom_factory())) }
pub fn seq(deps: impl IntoIterator<Item = GExpr>, val: GExpr) -> GExpr {
fn recur(mut ops: impl Iterator<Item = GExpr>) -> Option<GExpr> {
let op = ops.next()?;
Some(match recur(ops) {
None => op,
Some(rec) => inherit(GExprKind::Seq(Box::new(op), Box::new(rec))),
})
}
recur(deps.into_iter().chain([val])).expect("Empty list provided to seq!")
}
pub fn arg(n: u64) -> GExpr { inherit(GExprKind::Arg(n)) }
pub fn lambda(n: u64, [b]: [GExpr; 1]) -> GExpr { inherit(GExprKind::Lambda(n, Box::new(b))) }
pub fn call(f: GExpr, argv: impl IntoIterator<Item = GExpr>) -> GExpr {
(argv.into_iter()).fold(f, |f, x| inherit(GExprKind::Call(Box::new(f), Box::new(x))))
}
pub fn bot(ev: impl IntoIterator<Item = OrcErr>) -> GExpr {
inherit(GExprKind::Bottom(OrcErrv::new(ev).unwrap()))
}