generatox_proc/
lib.rs

1use crate::transform::Transformer;
2use parse::YieldFn;
3use quote::quote;
4use syn::{fold::Fold, parse_macro_input, parse_quote, GenericParam, LifetimeParam};
5use transform::DefineLifetimes;
6
7mod parse;
8mod transform;
9
10#[proc_macro]
11pub fn generator(body: proc_macro::TokenStream) -> proc_macro::TokenStream {
12    let YieldFn {
13        attrs,
14        vis,
15        mut sig,
16        yield_ty: ty,
17        block,
18        ..
19    } = parse_macro_input!(body as YieldFn);
20
21    let mut lts = DefineLifetimes::default();
22    sig = lts.fold_signature(sig);
23    sig.generics.params.extend(
24        lts.unique
25            .iter()
26            .cloned()
27            .map(|x| GenericParam::Lifetime(LifetimeParam::new(x))),
28    );
29
30    // let lts = lts.lts.iter().fold(TokenStream::new(), |prev, x| quote!(#prev #x +));
31    let lts = lts.unique.map(|x| quote!(#x +));
32
33    let block = Transformer(&ty).fold_block(block);
34    let (arrow, output) = match sig.output {
35        syn::ReturnType::Default => (Default::default(), parse_quote!(())),
36        syn::ReturnType::Type(arrow, output) => (arrow, output),
37    };
38
39    sig.output = parse_quote! {
40        #arrow impl #lts ::generatox::Generator<Yield = #ty, Return = #output>
41    };
42
43    return quote! {
44        #(#attrs)*
45        #vis #sig {
46            ::generatox::wrapper::Wrapper::new(async move #block)
47        }
48    }
49    .into();
50}