use std::borrow::Cow; use never::Never; use orchid_base::fmt; use orchid_extension::conv::ToExpr; use orchid_extension::coroutine_exec::exec; use orchid_extension::expr::Expr; use orchid_extension::gen_expr::new_atom; use orchid_extension::{Atomic, OwnedAtom, OwnedVariant, TAtom}; use crate::macros::mactree::{MacTok, MacTree}; #[derive(Clone)] pub struct InstantiateTplCall { pub(crate) tpl: MacTree, pub(crate) argc: usize, pub(crate) argv: Vec, } impl Atomic for InstantiateTplCall { type Variant = OwnedVariant; type Data = (); } impl OwnedAtom for InstantiateTplCall { async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) } type Refs = Never; // Technically must be supported but shouldn't actually ever be called async fn call_ref(&self, arg: Expr) -> impl ToExpr { if !self.argv.is_empty() { eprintln!( "Copying partially applied instantiate_tpl call. This is an internal value.\ \nIt should be fully consumed within generated code." ); } self.clone().call(arg).await } async fn call(mut self, arg: Expr) -> impl ToExpr { exec(async move |mut h| { match h.exec::>(arg.clone()).await { Err(_) => panic!("Expected a macro param, found {}", fmt(&arg).await), Ok(t) => self.argv.push(t.own().await), }; if self.argv.len() < self.argc { return new_atom(self); } let mut args = self.argv.into_iter(); let ret = self.tpl.map(&mut false, &mut |mt| match mt.tok() { MacTok::Slot => Some(args.next().expect("Not enough arguments to fill all slots")), _ => None, }); assert!(args.next().is_none(), "Too many arguments for all slots"); new_atom(ret) }) .await } }