84 lines
2.9 KiB
Rust
84 lines
2.9 KiB
Rust
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<GenMember> {
|
|
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<MacTree>, right: Int| async move {
|
|
InstantiateTplCall {
|
|
tpl: own(tpl).await,
|
|
argc: right.0.try_into().unwrap(),
|
|
argv: Vec::new(),
|
|
}
|
|
}),
|
|
),
|
|
fun(true, "resolve", |tpl: TypAtom<MacTree>| async move {
|
|
call([
|
|
sym_ref(sym!(macro::resolve_recur; tpl.untyped.ctx().i()).await),
|
|
atom(RecurState::Bottom),
|
|
tpl.untyped.ex().to_expr().await,
|
|
])
|
|
}),
|
|
fun(true, "lower", |tpl: TypAtom<MacTree>| 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().errv() { Err(e) } else { Ok(res) }
|
|
}),
|
|
fun(true, "resolve_recur", |state: TypAtom<RecurState>, tpl: TypAtom<MacTree>| async move {
|
|
exec(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::<TypAtom<Macro>>(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
|
|
}),
|
|
])
|
|
}
|