Added support for defining macros in Rust within the macro system
Also fixed a lot of bugs
This commit is contained in:
166
orchid-std/src/macros/utils.rs
Normal file
166
orchid-std/src/macros/utils.rs
Normal file
@@ -0,0 +1,166 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use async_fn_stream::stream;
|
||||
use futures::StreamExt;
|
||||
use itertools::{Itertools, chain};
|
||||
use orchid_base::name::{NameLike, Sym, VPath};
|
||||
use orchid_extension::conv::ToExpr;
|
||||
use orchid_extension::gen_expr::sym_ref;
|
||||
use orchid_extension::tree::{GenMember, MemKind, cnst, lazy};
|
||||
|
||||
use crate::macros::macro_value::{Macro, MacroData, Matcher, Rule};
|
||||
use crate::macros::mactree::map_mactree_v;
|
||||
use crate::macros::rule::matcher::{NamedMatcher, PriodMatcher};
|
||||
use crate::{MacTok, MacTree};
|
||||
|
||||
pub(crate) fn mk_macro<B: ToExpr + Clone + 'static>(
|
||||
prio: Option<u64>,
|
||||
own_kws: impl IntoIterator<Item = &'static str>,
|
||||
rules: impl IntoIterator<Item = (Vec<MacTree>, B)>,
|
||||
) -> Vec<GenMember> {
|
||||
let own_kws = own_kws.into_iter().collect_vec();
|
||||
let name = own_kws[0];
|
||||
let (patterns, bodies) = rules.into_iter().unzip::<_, _, Vec<Vec<MacTree>>, Vec<B>>();
|
||||
let main_const = lazy(true, name, async move |path, ctx| {
|
||||
let module = (Sym::new(path.split_last_seg().1.iter().cloned(), ctx.i()).await)
|
||||
.expect("Default macro in global root");
|
||||
MemKind::Const(
|
||||
Macro(Rc::new(MacroData {
|
||||
module,
|
||||
prio,
|
||||
rules: stream(async |mut h| {
|
||||
for (counter, pat) in patterns.into_iter().enumerate() {
|
||||
let mut placeholders = Vec::new();
|
||||
map_mactree_v(&pat, &mut false, &mut |tt| {
|
||||
if let MacTok::Ph(ph) = &*tt.tok {
|
||||
placeholders.push(ph.name.clone())
|
||||
}
|
||||
None
|
||||
});
|
||||
let pattern = match prio {
|
||||
Some(_) => Matcher::Priod(PriodMatcher::new(&pat, ctx.i()).await.unwrap()),
|
||||
None => Matcher::Named(NamedMatcher::new(&pat, ctx.i()).await.unwrap()),
|
||||
};
|
||||
h.emit(Rule {
|
||||
glossary: pat.iter().flat_map(|t| t.glossary()).cloned().collect(),
|
||||
pattern,
|
||||
placeholders,
|
||||
body_name: ctx.i().i(&format!("({name})::{counter}")).await,
|
||||
})
|
||||
.await;
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
.await,
|
||||
}))
|
||||
.to_expr()
|
||||
.await,
|
||||
)
|
||||
});
|
||||
let kw_consts = own_kws[1..].iter().flat_map(|kw| {
|
||||
lazy(true, kw, async |path, ctx| {
|
||||
let name = VPath::new(path.split_last_seg().1.iter().cloned())
|
||||
.name_with_suffix(ctx.i().i(*kw).await)
|
||||
.to_sym(ctx.i())
|
||||
.await;
|
||||
MemKind::Const(sym_ref(name))
|
||||
})
|
||||
});
|
||||
let body_consts = (bodies.into_iter().enumerate())
|
||||
.flat_map(|(counter, body)| cnst(false, &format!("({name})::{counter}"), body));
|
||||
chain!(main_const, kw_consts, body_consts).collect()
|
||||
}
|
||||
|
||||
macro_rules! mactree {
|
||||
($i:expr; $($body:tt)*) => {
|
||||
$crate::macros::utils::mactreev!($i; ($($body)*)).remove(0)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! mactreev {
|
||||
(@RECUR $i:expr; $ret:ident) => {};
|
||||
(@RECUR $i:expr; $ret:ident "..$" $name:ident $prio:literal $($tail:tt)*) => {
|
||||
ret.push(MacTok::Ph(Ph{
|
||||
name: i.i(stringify!($name)).await,
|
||||
kind: PhKind::Vector{ at_least_one: false, priority: $prio }
|
||||
}).at(Pos::Inherit));
|
||||
mactreev!(@RECUR $i; $ret $($tail)*);
|
||||
};
|
||||
(@RECUR $i:expr; $ret:ident "...$" $name:ident $prio:literal $($tail:tt)*) => {
|
||||
$ret.push(MacTok::Ph(Ph{
|
||||
name: $i.i(stringify!($name)).await,
|
||||
kind: $crate::macros::mactree::PhKind::Vector{ at_least_one: true, priority: $prio }
|
||||
}).at(orchid_base::location::Pos::Inherit));
|
||||
mactreev!(@RECUR $i; $ret $($tail)*);
|
||||
};
|
||||
(@RECUR $i:expr; $ret:ident "$" $name:ident $($tail:tt)*) => {
|
||||
$ret.push(MacTok::Ph(Ph{
|
||||
name: $i.i(stringify!(name)).await,
|
||||
kind: $crate::macros::mactree::PhKind::Scalar
|
||||
}).at(orchid_base::location::Pos::Inherit));
|
||||
mactreev!(@RECUR $i; $ret $($tail)*);
|
||||
};
|
||||
(@RECUR $i:expr; $ret:ident "'" $arg:expr ; $($tail:tt)*) => {
|
||||
$ret.push(MacTok::Value($arg).at(orchid_base::location::Pos::Inherit));
|
||||
mactreev!(@RECUR $i; $ret $($tail)*);
|
||||
};
|
||||
(@RECUR $i:expr; $ret:ident "" $arg:expr ; $($tail:tt)*) => {
|
||||
$ret.push($arg);
|
||||
mactreev!(@RECUR $i; $ret $($tail)*);
|
||||
};
|
||||
(@RECUR $i:expr; $ret:ident "l_" $arg:expr ; ($($body:tt)*) $($tail:tt)*) => {
|
||||
$ret.push(MacTok::Lambda(
|
||||
MacTok::Value($arg).at(orchid_base::location::Pos::Inherit),
|
||||
mactreev!(i; $($body)*)
|
||||
).at(Pos::Inherit));
|
||||
mactreev!(@RECUR $i; $ret $($tail)*);
|
||||
};
|
||||
(@RECUR $i:expr; $ret:ident "l" $argh:tt $(:: $arg:tt)* ($($body:tt)*) $($tail:tt)*) => {
|
||||
$ret.push(MacTok::Lambda(
|
||||
MacTok::Name(sym!($argh $(:: $arg)*; $i).await).at(orchid_base::location::Pos::Inherit),
|
||||
mactreev!(i; $($body)*)
|
||||
).at(orchid_base::location::Pos::Inherit));
|
||||
mactreev!(@RECUR $i; $ret $($tail)*);
|
||||
};
|
||||
(@RECUR $i:expr; $ret:ident ( $($body:tt)* ) $($tail:tt)*) => {
|
||||
$ret.push(
|
||||
MacTok::S(orchid_base::tree::Paren::Round, mactreev!($i; $($body)*))
|
||||
.at(orchid_base::location::Pos::Inherit)
|
||||
);
|
||||
mactreev!(@RECUR $i; $ret $($tail)*);
|
||||
};
|
||||
(@RECUR $i:expr; $ret:ident [ $($body:tt)* ] $($tail:tt)*) => {
|
||||
$ret.push(
|
||||
MacTok::S(orchid_base::tree::Paren::Square, mactreev!($i; $($body)*))
|
||||
.at(orchid_base::location::Pos::Inherit)
|
||||
);
|
||||
mactreev!(@RECUR $i; $ret $($tail)*);
|
||||
};
|
||||
(@RECUR $i:expr; $ret:ident { $($body:tt)* } $($tail:tt)*) => {
|
||||
$ret.push(
|
||||
MacTok::S(orchid_base::tree::Paren::Curly, mactreev!($i; $($body)*))
|
||||
.at(orchid_base::location::Pos::Inherit)
|
||||
);
|
||||
mactreev!(@RECUR $i; $ret $($tail)*);
|
||||
};
|
||||
(@RECUR $i:expr; $ret:ident $nhead:tt $($tail:tt)*) => {
|
||||
mactreev!(@NAME_MUNCHER $i; $ret ($nhead) $($tail)*)
|
||||
};
|
||||
(@NAME_MUNCHER $i:expr; $ret:ident ($($munched:tt)*) :: $name:tt $($tail:tt)*) => {
|
||||
mactreev!(@NAME_MUNCHER $i; $ret ($($munched)* :: $name) $($tail)*)
|
||||
};
|
||||
(@NAME_MUNCHER $i:expr; $ret:ident ($($munched:tt)*) $($tail:tt)*) => {
|
||||
let sym = orchid_base::sym!($($munched)* ; $i).await;
|
||||
$ret.push(MacTok::Name(sym).at(orchid_base::location::Pos::Inherit));
|
||||
mactreev!(@RECUR $i; $ret $($tail)*);
|
||||
};
|
||||
($i:expr; ) => { Vec::new() };
|
||||
($i:expr; $($tail:tt)*) => {
|
||||
{
|
||||
let mut ret = Vec::<MacTree>::new();
|
||||
mactreev!(@RECUR $i; ret $($tail)*);
|
||||
ret
|
||||
}
|
||||
};
|
||||
}
|
||||
pub(crate) use {mactree, mactreev};
|
||||
Reference in New Issue
Block a user