forked from Orchid/orchid
122 lines
3.9 KiB
Rust
122 lines
3.9 KiB
Rust
use async_fn_stream::stream;
|
|
use futures::{StreamExt, stream};
|
|
use orchid_base::{OrcRes, sym};
|
|
use orchid_extension::gen_expr::{GExpr, call, new_atom};
|
|
use orchid_extension::tree::{GenMember, fun, prefix};
|
|
use orchid_extension::{Expr, TAtom, ToExpr, exec};
|
|
|
|
use crate::macros::match_macros::{MatcherAtom, match_one};
|
|
use crate::macros::utils::{RuleCtx, build_macro, mactree, mactreev};
|
|
use crate::{HomoTpl, MacTree, OrcOpt};
|
|
|
|
pub async fn gen_tuple_macro_lib() -> Vec<GenMember> {
|
|
prefix("std::tuple", [
|
|
build_macro(None, ["t"])
|
|
.rule(mactreev!("std::tuple::t" [ "...$" elements 0 ]), async |mut cx, [elements]| {
|
|
let tup: HomoTpl<TAtom<MacTree>> =
|
|
cx.recur_call(mactree!("macros::common::comma_list" "push" elements)).await?;
|
|
let val = stream(async |mut h| {
|
|
for item in &tup.0[..] {
|
|
h.emit(cx.recur(item.own().await).await).await
|
|
}
|
|
})
|
|
.fold(mactree!("std::tuple::empty"), async |head, new| {
|
|
mactree!(
|
|
"std::tuple::cat"
|
|
"push" head;
|
|
("std::tuple::one"
|
|
"push" new)
|
|
)
|
|
})
|
|
.await;
|
|
Ok(val)
|
|
})
|
|
.rule(
|
|
mactreev!("pattern::match_rule"(
|
|
"std::tuple::t"[ "...$" elements 0 "macros::common::," "macros::common::.."]
|
|
)),
|
|
async |cx, [elements]| parse_tpl(cx, elements, Some(mactree!("macros::common::_"))).await,
|
|
)
|
|
.rule(
|
|
mactreev!("pattern::match_rule"(
|
|
"std::tuple::t"[ "...$" elements 1 "macros::common::," "macros::common::.." "...$" tail 0]
|
|
)),
|
|
async |cx, [elements, tail]| parse_tpl(cx, elements, Some(tail)).await,
|
|
)
|
|
.rule(
|
|
mactreev!("pattern::match_rule"("std::tuple::t"[ "...$" elements 0])),
|
|
async |cx, [elements]| parse_tpl(cx, elements, None).await,
|
|
)
|
|
.finish(),
|
|
fun(false, "matcher_body", tuple_matcher_body),
|
|
])
|
|
}
|
|
|
|
async fn parse_tpl(
|
|
mut cx: RuleCtx<'_>,
|
|
elements: MacTree,
|
|
tail_matcher: Option<MacTree>,
|
|
) -> OrcRes<MacTree> {
|
|
let tup: HomoTpl<TAtom<MacTree>> =
|
|
cx.recur_call(mactree!("macros::common::comma_list" "push" elements)).await?;
|
|
let mut keys = Vec::new();
|
|
let mut sub_matchers = mactree!("std::tuple::empty");
|
|
for mac_a in &tup.0[..] {
|
|
let sub: TAtom<MatcherAtom> =
|
|
cx.recur_call(mactree!("pattern::match_rule" ("push" mac_a.own().await))).await?;
|
|
let owned = sub.own().await;
|
|
keys.extend(owned.keys);
|
|
sub_matchers =
|
|
mactree!("std::tuple::cat" "push" sub_matchers; ("std::tuple::one" "push" owned.matcher));
|
|
}
|
|
let tail_matcher = match tail_matcher {
|
|
Some(mac) => {
|
|
let atm: TAtom<MatcherAtom> =
|
|
cx.recur_call(mactree!("pattern::match_rule" "push" mac)).await?;
|
|
let owned = atm.own().await;
|
|
keys.extend(owned.keys);
|
|
mactree!("std::option::some" "push" owned.matcher)
|
|
},
|
|
None => mactree!("std::option::none"),
|
|
};
|
|
Ok(mactree!("Val" new_atom(MatcherAtom {
|
|
keys,
|
|
matcher: mactree!("std::tuple::matcher_body" "push" sub_matchers; "push" tail_matcher),
|
|
})))
|
|
}
|
|
|
|
fn tuple_matcher_body(
|
|
children: HomoTpl<Expr>,
|
|
tail: OrcOpt<Expr>,
|
|
value: HomoTpl<Expr>,
|
|
) -> impl Future<Output = GExpr> {
|
|
exec(async move |mut h| -> OrcRes<OrcOpt<HomoTpl<Expr>>> {
|
|
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 match_one(&mut h, sub_mat.clone(), 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!(std::tuple::empty).to_gen().await, async |prefix, new| {
|
|
call(sym!(std::tuple::cat), (prefix, new.clone())).await
|
|
})
|
|
.await;
|
|
match match_one(&mut h, tail_mat, tail_tpl).await? {
|
|
OrcOpt(Some(tail_binds)) => binds.extend(tail_binds.0),
|
|
OrcOpt(None) => return Ok(OrcOpt(None)),
|
|
}
|
|
},
|
|
};
|
|
Ok(OrcOpt(Some(HomoTpl(binds))))
|
|
})
|
|
}
|