1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
mod tpl;

use proc_macro::TokenStream;
use proc_macro_error::proc_macro_error;
use quote::quote;
use syn::parse_macro_input;

#[proc_macro]
#[proc_macro_error]
pub fn render_string(input: TokenStream) -> TokenStream {
    let mut c = parse_macro_input!(input as syn::ExprCall);
    let arg: syn::Expr = syn::parse_quote!(&mut w);
    c.args.insert(0, arg);
    TokenStream::from(quote! {
        {
            let mut w = Vec::new();
            #c.unwrap();
            String::from_utf8(w).unwrap()
        }
    })
}

#[proc_macro]
#[proc_macro_error]
pub fn tpl(input: TokenStream) -> TokenStream {
    let el = parse_macro_input!(input as tpl::Template);
    let result = quote! { #el };
    TokenStream::from(result)
}

#[proc_macro_attribute]
#[proc_macro_error]
pub fn tplfn(_attr: TokenStream, item: TokenStream) -> TokenStream {
    let mut f = parse_macro_input!(item as syn::ItemFn);
    let arg: syn::FnArg = syn::parse_quote!(w: &mut dyn ::std::io::Write);
    f.sig.inputs.insert(0, arg);
    match f.sig.output {
        syn::ReturnType::Default => {
            f.sig.output = syn::parse_quote!(-> ::std::result::Result<(), ::std::io::Error>);
        }
        _ => (),
    }
    TokenStream::from(quote!(#f))
}

#[proc_macro]
#[proc_macro_error]
pub fn child(input: TokenStream) -> TokenStream {
    let mut c = parse_macro_input!(input as syn::ExprCall);
    let arg: syn::Expr = syn::parse_quote!(w);
    c.args.insert(0, arg);
    TokenStream::from(quote! {
        |w: &mut dyn ::std::io::Write| -> ::std::io::Result<()> {
            #c
        }
    })
}