use std::future::Future; use never::Never; use orchid_base::error::{OrcErrv, OrcRes, mk_errv}; use orchid_base::interner::Interner; use orchid_base::location::Pos; use crate::atom::{AtomicFeatures, ForeignAtom, ToAtom, TypAtom}; use crate::expr::Expr; use crate::gen_expr::{GExpr, atom, bot}; use crate::system::{SysCtx, downcast_atom}; pub trait TryFromExpr: Sized { fn try_from_expr(expr: Expr) -> impl Future>; } impl TryFromExpr for Expr { async fn try_from_expr(expr: Expr) -> OrcRes { Ok(expr) } } impl TryFromExpr for (T, U) { async fn try_from_expr(expr: Expr) -> OrcRes { Ok((T::try_from_expr(expr.clone()).await?, U::try_from_expr(expr).await?)) } } async fn err_not_atom(pos: Pos, i: &Interner) -> OrcErrv { mk_errv(i.i("Expected an atom").await, "This expression is not an atom", [pos]) } async fn err_type(pos: Pos, i: &Interner) -> OrcErrv { mk_errv(i.i("Type error").await, "The atom is a different type than expected", [pos]) } impl TryFromExpr for ForeignAtom { async fn try_from_expr(expr: Expr) -> OrcRes { match expr.atom().await { Err(ex) => Err(err_not_atom(ex.data().await.pos.clone(), ex.ctx().i()).await), Ok(f) => Ok(f), } } } impl TryFromExpr for TypAtom { async fn try_from_expr(expr: Expr) -> OrcRes { let f = ForeignAtom::try_from_expr(expr).await?; match downcast_atom::(f).await { Ok(a) => Ok(a), Err(f) => Err(err_type(f.pos(), f.ctx().i()).await), } } } impl TryFromExpr for SysCtx { async fn try_from_expr(expr: Expr) -> OrcRes { Ok(expr.ctx()) } } pub trait ToExpr { fn to_expr(self) -> impl Future; } impl ToExpr for GExpr { async fn to_expr(self) -> GExpr { self } } impl ToExpr for Expr { async fn to_expr(self) -> GExpr { self.slot() } } impl ToExpr for OrcRes { async fn to_expr(self) -> GExpr { match self { Err(e) => bot(e), Ok(t) => t.to_expr().await, } } } impl ToExpr for A { async fn to_expr(self) -> GExpr { atom(self) } } impl ToExpr for Never { async fn to_expr(self) -> GExpr { match self {} } }