use hashbrown::HashMap; use itertools::Itertools; use orchid_base::error::Reporter; use orchid_base::sym; use orchid_extension::atom::TypAtom; use orchid_extension::atom_owned::own; use orchid_extension::conv::ToExpr; use orchid_extension::coroutine_exec::exec; use orchid_extension::gen_expr::{atom, call, sym_ref}; use orchid_extension::reflection::{ReflMemKind, refl}; use orchid_extension::tree::{GenMember, comments, fun, prefix}; use substack::Substack; use crate::Int; use crate::macros::instantiate_tpl::InstantiateTplCall; use crate::macros::macro_line::{Macro, Matcher}; use crate::macros::mactree::{LowerCtx, MacTree}; use crate::macros::recur_state::RecurState; use crate::macros::resolve::{ResolveCtx, resolve}; pub fn gen_macro_lib() -> Vec { prefix("macros", [ comments( ["This is an internal function, you can't obtain a value of its argument type.", "hidden"], fun(true, "instantiate_tpl", |tpl: TypAtom, right: Int| async move { InstantiateTplCall { tpl: own(tpl).await, argc: right.0.try_into().unwrap(), argv: Vec::new(), } }), ), fun(true, "resolve", |tpl: TypAtom| async move { call([ sym_ref(sym!(macros::resolve_recur; tpl.untyped.ctx().i()).await), atom(RecurState::Bottom), tpl.untyped.ex().to_expr().await, ]) }), fun(true, "lower", |tpl: TypAtom| async move { let ctx = LowerCtx { sys: tpl.untyped.ctx().clone(), rep: &Reporter::new() }; let res = own(tpl).await.lower(ctx, Substack::Bottom).await; if let Some(e) = Reporter::new().res() { Err(e) } else { Ok(res) } }), fun(true, "resolve_recur", |state: TypAtom, tpl: TypAtom| async move { exec("macros::resolve_recur", async move |mut h| { let ctx = tpl.ctx().clone(); let root = refl(&ctx); let tpl = own(tpl.clone()).await; let mut macros = HashMap::new(); for n in tpl.glossary() { if let Ok(ReflMemKind::Const) = root.get_by_path(n).await.map(|m| m.kind()) { let Ok(mac) = h.exec::>(sym_ref(n.clone())).await else { continue }; let mac = own(mac).await; macros.entry(mac.0.own_kws[0].clone()).or_insert(mac); } } let mut named = HashMap::new(); let mut priod = Vec::new(); for (_, mac) in macros.iter() { for rule in mac.0.rules.iter() { if rule.glossary.is_subset(tpl.glossary()) { match &rule.pattern { Matcher::Named(m) => named.entry(m.head()).or_insert(Vec::new()).push((m, mac, rule)), Matcher::Priod(p) => priod.push((mac.0.prio, (p, mac, rule))), } } } } let priod = priod.into_iter().sorted_unstable_by_key(|(p, _)| *p).map(|(_, r)| r).collect(); let mut rctx = ResolveCtx { h, recur: own(state).await, ctx: ctx.clone(), named, priod }; let resolve_res = resolve(&mut rctx, &tpl).await; std::mem::drop(rctx); match resolve_res { Some(out_tree) => out_tree.to_expr().await, None => tpl.to_expr().await, } }) .await }), ]) }