Added support for defining macros in Rust within the macro system

Also fixed a lot of bugs
This commit is contained in:
2025-09-30 21:23:16 +02:00
parent 7971a2b4eb
commit b77653f841
52 changed files with 849 additions and 502 deletions

View File

@@ -6,6 +6,7 @@ use futures::FutureExt;
use futures::future::join_all;
use hashbrown::HashSet;
use itertools::Itertools;
use orchid_api_derive::Coding;
use orchid_base::error::{OrcErrv, Reporter, mk_errv};
use orchid_base::format::{FmtCtx, FmtUnit, Format, Variants, fmt};
use orchid_base::interner::Tok;
@@ -42,38 +43,56 @@ impl MacTree {
MacTok::Bottom(e) => bot(e.clone()),
MacTok::Lambda(arg, body) => {
let MacTok::Name(name) = &*arg.tok else {
let err = mk_errv(
return bot(mk_errv(
ctx.sys.i().i("Syntax error after macros").await,
"This token ends up as a binding, consider replacing it with a name",
[arg.pos()],
);
ctx.rep.report(err.clone());
return bot(err);
));
};
lambda(args.len() as u64, lower_v(body, ctx, args.push(name.clone())).await)
let arg_pos = args.len() as u64;
let args = args.push(name.clone());
let body = match &body[..] {
[] => bot(mk_errv(
ctx.sys.i().i("Empty lambda body").await,
"Lambdas must evaluate to an expression",
[self.pos()],
)),
[f, argv @ ..] => call(
f.lower(ctx.clone(), args.clone()).boxed_local().await,
lower_v(argv, ctx, args).await,
),
};
lambda(arg_pos, body)
},
MacTok::Name(name) => match args.iter().enumerate().find(|(_, n)| *n == name) {
None => sym_ref(name.clone()),
Some((i, _)) => arg((args.len() - i) as u64),
Some((i, _)) => arg((args.len() - i - 1) as u64),
},
MacTok::Ph(ph) => {
let err = mk_errv(
return bot(mk_errv(
ctx.sys.i().i("Placeholder in value").await,
format!("Placeholder {ph} is only supported in macro patterns"),
[self.pos()],
);
ctx.rep.report(err.clone());
return bot(err);
));
},
MacTok::S(Paren::Round, body) => match &body[..] {
[fun, argv @ ..] => call(
fun.lower(ctx.clone(), args.clone()).boxed_local().await,
lower_v(argv, ctx, args).await,
),
[] =>
return bot(mk_errv(
ctx.sys.i().i("Empty ()").await,
"Empty () is not a meaningful expression",
[self.pos()],
)),
},
MacTok::S(Paren::Round, body) => call(lower_v(body, ctx, args).await),
MacTok::S(..) => {
let err = mk_errv(
return bot(mk_errv(
ctx.sys.i().i("[] or {} after macros").await,
format!("{} didn't match any macro", fmt(self, ctx.sys.i()).await),
[self.pos()],
);
ctx.rep.report(err.clone());
return bot(err);
));
},
MacTok::Slot => panic!("Uninstantiated template should never be exposed"),
MacTok::Value(v) => v.clone().to_expr().await,
@@ -90,7 +109,8 @@ impl OwnedAtom for MacTree {
async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) }
async fn print_atom<'a>(&'a self, c: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit {
self.tok.print(c).await
tl_cache!(Rc<Variants>: Rc::new(Variants::default().bounded("'{0}")))
.units([self.tok.print(c).await])
}
}
impl Format for MacTree {
@@ -134,22 +154,18 @@ impl Format for MacTok {
async fn print<'a>(&'a self, c: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit {
match self {
Self::Value(v) => v.print(c).await,
Self::Lambda(arg, b) => FmtUnit::new(
tl_cache!(Rc<Variants>: Rc::new(Variants::default()
.unbounded("\\{0b}.{1l}")
.bounded("(\\{0b}.{1b})"))),
[arg.print(c).boxed_local().await, mtreev_fmt(b, c).await],
),
Self::Lambda(arg, b) => tl_cache!(Rc<Variants>: Rc::new(Variants::default()
.unbounded("\\{0} {1l}")
.bounded("(\\{0} {1b})")))
.units([arg.print(c).boxed_local().await, mtreev_fmt(b, c).await]),
Self::Name(n) => format!("{n}").into(),
Self::Ph(ph) => format!("{ph}").into(),
Self::S(p, body) => FmtUnit::new(
match *p {
Paren::Round => Rc::new(Variants::default().bounded("({0b})")),
Paren::Curly => Rc::new(Variants::default().bounded("{{0b}}")),
Paren::Square => Rc::new(Variants::default().bounded("[{0b}]")),
},
[mtreev_fmt(body, c).await],
),
Self::S(p, body) => match *p {
Paren::Round => tl_cache!(Rc<Variants>: Rc::new(Variants::default().bounded("({0b})"))),
Paren::Curly => tl_cache!(Rc<Variants>: Rc::new(Variants::default().bounded("{{0b}}"))),
Paren::Square => tl_cache!(Rc<Variants>: Rc::new(Variants::default().bounded("[{0b}]"))),
}
.units([mtreev_fmt(body, c).await]),
Self::Slot => "$SLOT".into(),
Self::Bottom(err) if err.len() == 1 => format!("Bottom({}) ", err.one().unwrap()).into(),
Self::Bottom(err) => format!("Botttom(\n{}) ", indent(&err.to_string())).into(),
@@ -181,7 +197,7 @@ impl Display for Ph {
}
}
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, Coding)]
pub enum PhKind {
Scalar,
Vector { at_least_one: bool, priority: u8 },