Updated macro system to process and return mactree and then lower it separately to gexpr
Some checks failed
Rust / build (push) Has been cancelled
Some checks failed
Rust / build (push) Has been cancelled
This commit is contained in:
80
orchid-std/src/macros/lower.rs
Normal file
80
orchid-std/src/macros/lower.rs
Normal 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
|
||||
}
|
||||
Reference in New Issue
Block a user