Added support for defining macros in Rust within the macro system
Also fixed a lot of bugs
This commit is contained in:
@@ -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 },
|
||||
|
||||
Reference in New Issue
Block a user