use std::borrow::Cow; use never::Never; use orchid_base::format::fmt; use orchid_extension::atom::{Atomic, TAtom}; use orchid_extension::atom_owned::{OwnedAtom, OwnedVariant, own}; use orchid_extension::context::i; use orchid_extension::conv::ToExpr; use orchid_extension::coroutine_exec::exec; use orchid_extension::expr::Expr; use orchid_extension::gen_expr::GExpr; 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) -> GExpr { 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) -> GExpr { exec(async move |mut h| { match h.exec::>(arg.clone()).await { Err(_) => panic!("Expected a macro param, found {}", fmt(&arg, &i()).await), Ok(t) => self.argv.push(own(&t).await), }; if self.argv.len() < self.argc { return self.to_gen().await; } 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"); ret.to_gen().await }) .await .to_gen() .await } }