forked from Orchid/orchid
178 lines
5.6 KiB
Rust
178 lines
5.6 KiB
Rust
use futures::{StreamExt, stream};
|
|
use orchid_base::error::OrcRes;
|
|
use orchid_base::sym;
|
|
use orchid_extension::atom::TAtom;
|
|
use orchid_extension::atom_owned::own;
|
|
use orchid_extension::context::i;
|
|
use orchid_extension::conv::ToExpr;
|
|
use orchid_extension::coroutine_exec::exec;
|
|
use orchid_extension::expr::Expr;
|
|
use orchid_extension::gen_expr::{GExpr, call, sym_ref};
|
|
use orchid_extension::tree::{GenMember, fun, prefix};
|
|
|
|
use crate::macros::match_macros::MatcherAtom;
|
|
use crate::macros::resolve::resolve;
|
|
use crate::macros::utils::{build_macro, mactree, mactreev};
|
|
use crate::{HomoTpl, MacTree, OrcOpt, Tpl};
|
|
|
|
pub async fn gen_std_macro_lib() -> Vec<GenMember> {
|
|
prefix("std", [
|
|
prefix("option", [
|
|
fun(false, "is_some_body", |sub: TAtom<MatcherAtom>, val: OrcOpt<Expr>| {
|
|
exec(async move |mut h| {
|
|
let Some(sub_val) = val.0 else { return Ok(OrcOpt(None)) };
|
|
h.exec::<OrcOpt<Expr>>(call(sub.to_gen().await, [sub_val.to_gen().await])).await
|
|
})
|
|
}),
|
|
fun(false, "is_none_body", async |val: OrcOpt<Expr>| {
|
|
if val.0.is_none() { OrcOpt(Some(Tpl(()))) } else { OrcOpt(None) }
|
|
}),
|
|
build_macro(None, ["of", "empty"])
|
|
.rule(mactreev!(pattern::match_rule ( std::option::of "...$" sub_pattern 0)), [
|
|
|[sub]: [_; _]| {
|
|
exec(async move |mut h| {
|
|
let sub = h
|
|
.exec::<TAtom<MatcherAtom>>(
|
|
resolve(mactree!(pattern::match_rule "push" sub;)).await,
|
|
)
|
|
.await?;
|
|
Ok(MatcherAtom {
|
|
keys: sub.keys().collect().await,
|
|
matcher: h
|
|
.register(call(sym_ref(sym!(std::option::is_some_body; i())), [sub
|
|
.to_gen()
|
|
.await]))
|
|
.await,
|
|
})
|
|
})
|
|
},
|
|
])
|
|
.rule(mactreev!(pattern::match_rule(std::option::empty)), [|[]: [_; _]| {
|
|
exec(async |mut h| {
|
|
Ok(MatcherAtom {
|
|
keys: vec![],
|
|
matcher: h.register(sym_ref(sym!(std::option::is_none_body; i()))).await,
|
|
})
|
|
})
|
|
}])
|
|
.finish(),
|
|
]),
|
|
prefix("tuple", [
|
|
build_macro(None, ["t"])
|
|
.rule(mactreev!(std::tuple::t [ "...$" elements 0 ]), [|[elements]: [_; _]| {
|
|
exec(async move |mut h| {
|
|
let tup = h
|
|
.exec::<HomoTpl<TAtom<MacTree>>>(call(sym_ref(sym!(macros::resolve; i())), [
|
|
mactree!((macros::common::comma_list "push" elements ;)).to_gen().await,
|
|
]))
|
|
.await?;
|
|
let val = stream::iter(&tup.0[..])
|
|
.fold(sym_ref(sym!(std::tuple::empty; i())), async |head, new| {
|
|
call(sym_ref(sym!(std::tuple::cat; i())), [
|
|
head,
|
|
call(sym_ref(sym!(std::tuple::one; i())), [call(
|
|
sym_ref(sym!(macros::resolve; i())),
|
|
[new.clone().to_gen().await],
|
|
)]),
|
|
])
|
|
})
|
|
.await;
|
|
Ok(val)
|
|
})
|
|
}])
|
|
.rule(
|
|
mactreev!(pattern::match_rule(std::tuple::t[ "...$" elements 0 macros::common::..])),
|
|
[async |[elements]: [_; _]| parse_tpl(elements, Some(mactree!(macros::common::_))).await],
|
|
)
|
|
.rule(
|
|
mactreev!(pattern::match_rule(
|
|
std::tuple::t[ "...$" elements 1 macros::common::.. "...$" tail 0]
|
|
)),
|
|
[async |[elements, tail]: [_; _]| parse_tpl(elements, Some(tail)).await],
|
|
)
|
|
.rule(mactreev!(pattern::match_rule(std::tuple::t[ "...$" elements 0])), [
|
|
|[elements]: [_; _]| parse_tpl(elements, None),
|
|
])
|
|
.finish(),
|
|
fun(false, "matcher_body", tuple_matcher_body),
|
|
]),
|
|
])
|
|
}
|
|
|
|
fn parse_tpl(elements: MacTree, tail_matcher: Option<MacTree>) -> impl Future<Output = GExpr> {
|
|
exec(async move |mut h| -> OrcRes<MatcherAtom> {
|
|
let tup = h
|
|
.exec::<HomoTpl<TAtom<MacTree>>>(call(sym_ref(sym!(macros::resolve; i())), [
|
|
mactree!((macros::common::comma_list "push" elements ;)).to_gen().await,
|
|
]))
|
|
.await?;
|
|
let mut subs = Vec::with_capacity(tup.0.len());
|
|
for mac_a in &tup.0[..] {
|
|
let mac = own(mac_a).await;
|
|
let sub = h
|
|
.exec::<TAtom<MatcherAtom>>(call(sym_ref(sym!(macros::resolve; i())), [
|
|
mactree!(pattern::match_rule "push" mac ;).to_gen().await,
|
|
]))
|
|
.await?;
|
|
subs.push(sub);
|
|
}
|
|
let tail_matcher = match tail_matcher {
|
|
Some(mac) => Some(
|
|
h.exec::<TAtom<MatcherAtom>>(call(sym_ref(sym!(macros::resolve; i())), [
|
|
mactree!(pattern::match_rule "push" mac ;).to_gen().await,
|
|
]))
|
|
.await?,
|
|
),
|
|
None => None,
|
|
};
|
|
Ok(MatcherAtom {
|
|
keys: stream::iter(&subs[..])
|
|
.flat_map(|t| t.keys())
|
|
.chain(stream::iter(&tail_matcher).flat_map(|mat| mat.keys()))
|
|
.collect()
|
|
.await,
|
|
matcher: call(sym_ref(sym!(std::tuple::matcher_body; i())), [
|
|
HomoTpl(subs).to_gen().await,
|
|
OrcOpt(tail_matcher).to_gen().await,
|
|
])
|
|
.to_expr()
|
|
.await,
|
|
})
|
|
})
|
|
}
|
|
|
|
fn tuple_matcher_body(
|
|
children: HomoTpl<TAtom<MatcherAtom>>,
|
|
tail: OrcOpt<TAtom<MatcherAtom>>,
|
|
value: HomoTpl<Expr>,
|
|
) -> impl Future<Output = GExpr> {
|
|
exec(async move |mut h| -> OrcRes<OrcOpt<GExpr>> {
|
|
if value.0.len() < children.0.len() {
|
|
return Ok(OrcOpt(None));
|
|
}
|
|
let mut binds = Vec::new();
|
|
for (sub_mat, sub_val) in children.0.iter().zip(&value.0) {
|
|
match sub_mat.run_matcher(&mut h, sub_val.clone()).await? {
|
|
OrcOpt(None) => return Ok(OrcOpt(None)),
|
|
OrcOpt(Some(subres)) => binds.extend(subres.0),
|
|
}
|
|
}
|
|
match tail.0 {
|
|
None if children.0.len() < value.0.len() => return Ok(OrcOpt(None)),
|
|
None => (),
|
|
Some(tail_mat) => {
|
|
let tail_tpl = stream::iter(&value.0[children.0.len()..])
|
|
.fold(sym_ref(sym!(std::tuple::empty; i())), async |prefix, new| {
|
|
call(sym_ref(sym!(std::tuple::cat; i())), [prefix, new.clone().to_gen().await])
|
|
})
|
|
.await;
|
|
match tail_mat.run_matcher(&mut h, tail_tpl).await? {
|
|
OrcOpt(Some(tail_binds)) => binds.extend(tail_binds.0),
|
|
OrcOpt(None) => return Ok(OrcOpt(None)),
|
|
}
|
|
},
|
|
};
|
|
todo!()
|
|
})
|
|
}
|