Updated macro system to process and return mactree and then lower it separately to gexpr
Some checks failed
Rust / build (push) Has been cancelled

This commit is contained in:
2026-04-11 11:00:22 +00:00
parent 9b4c7fa7d7
commit b44f3c1832
14 changed files with 460 additions and 469 deletions

View File

@@ -0,0 +1,80 @@
use std::collections::VecDeque;
use async_fn_stream::stream;
use futures::{FutureExt, StreamExt, stream};
use itertools::Itertools;
use orchid_base::{OrcErrv, Paren, Sym, fmt, is, mk_errv, report};
use orchid_extension::ToExpr;
use orchid_extension::gen_expr::{GExpr, GExprKind, bot, call};
use substack::Substack;
use crate::macros::mactree::MacTreeSeq;
use crate::{MacTok, MacTree};
fn on_err(e: OrcErrv) -> GExpr {
report(e.clone());
bot(e)
}
pub async fn lower(mt: &MacTree, args: Substack<'_, Sym>) -> GExpr {
match mt.tok() {
MacTok::Bottom(b) => on_err(b.clone()),
MacTok::Slot => on_err(mk_errv(
is("Lowering intermediary slotted mactree").await,
"Found a Slot during lowering, which should only exist in temporary templates",
[mt.pos()],
)),
MacTok::Ph(ph) => on_err(mk_errv(
is("Lowering placeholder").await,
format!("Found {ph} during lowering. Placeholders should only exist in macro patterns"),
[mt.pos()],
)),
MacTok::S(Paren::Curly | Paren::Square, _) => on_err(mk_errv(
is("Lowering {...} or [...]").await,
format!("Cannot lower this syntax, probable incorrect macro call: {}", fmt(mt).await),
[mt.pos()],
)),
MacTok::S(Paren::Round, b) if b.items.is_empty() => on_err(mk_errv(
is("Cannot lower empty ()").await,
"Attempted to lower empty (). All expressions must have a value.",
[mt.pos()],
)),
MacTok::Lambda(arg, body) => {
let MacTok::Name(n) = arg.tok() else {
return on_err(mk_errv(
is("Lowering lambda with complex param").await,
format!("In code after macros, lambda params can only be names, not {}", fmt(arg).await),
[arg.pos()],
));
};
if body.items.is_empty() {
return on_err(mk_errv(
is("Lowering lambda with empty body").await,
"Lambdas without a body are invalid, all expressions in Orchid must have a value",
[mt.pos()],
));
}
let body = lower_seq(body, args.push(n.clone())).await;
GExprKind::Lambda(Box::new(body)).at(mt.pos())
},
MacTok::S(Paren::Round, body) => lower_seq(body, args).await,
MacTok::Name(n) => match args.iter().find_position(|b| *b == n) {
Some((i, _)) => GExprKind::Arg(i.try_into().unwrap()).at(mt.pos()),
None => n.clone().to_gen().await,
},
MacTok::Value(expr) => expr.clone().to_gen().await,
}
}
pub async fn lower_seq(mtv: &MacTreeSeq, args: Substack<'_, Sym>) -> GExpr {
let mut exprs = stream(async |mut h| {
for mt in mtv.items.iter() {
h.emit(lower(mt, args.clone()).await).await
}
})
.collect::<VecDeque<_>>()
.boxed_local()
.await;
let first = exprs.pop_front().expect("We checked first that it isn't empty");
stream::iter(exprs).fold(first, async |f, x| call(f, x).await).await
}