pub(crate) use syn::{parse::{Parse, ParseStream}, parse_macro_input};
pub(crate) use quote::{
quote, ToTokens,
};
pub(crate)struct Comp {
mapping: Mapping,
for_if: ForIfClause
}
impl Parse for Comp {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
Ok(Self {
mapping: input.parse()?,
for_if: input.parse()?
})
}
}
impl ToTokens for Comp {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
let mapping = &self.mapping.0;
let ForIfClause {
pat,
expr: it,
conds
} = &self.for_if;
let conds = conds.iter().map(|c| {
let i = &c.0;
quote! {
#i
}
});
tokens.extend(quote! {
::core::iter::IntoIterator::into_iter(#it).filter_map(|#pat|{
(true #(&& (#conds))*).then(|| #mapping)
})
});
}
}
pub(crate) struct Mapping(syn::Expr);
impl Parse for Mapping {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
Ok(Self(input.parse()?))
}
}
pub(crate) struct ForIfClause {
pat: Pattern,
expr: syn::Expr,
conds: Vec<Condition>,
}
impl Parse for ForIfClause {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
input.parse::<syn::Token![for]>()?;
let pat = input.parse()?;
input.parse::<syn::Token![in]>()?;
let expr = input.parse()?;
let conds = parse_zero_or_more(input);
Ok(Self { pat, expr, conds })
}
}
pub(crate) struct Pattern(syn::Pat);
impl Parse for Pattern {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
Ok(Self(syn::Pat::parse_single(input)?))
}
}
impl ToTokens for Pattern {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
self.0.to_tokens(tokens);
}
}
pub(crate) struct Condition(syn::Expr);
impl Parse for Condition {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
input.parse::<syn::Token![if]>()?;
Ok(Self(input.parse()?))
}
}
fn parse_zero_or_more<T: Parse>(input: ParseStream) -> Vec<T>
{
let mut result = vec![];
while let Ok(i) = input.parse() {
result.push(i)
}
result
}