larpa_derive/
lib.rs

1mod attr;
2mod codegen;
3mod input;
4mod meta;
5mod name;
6mod respan;
7
8use proc_macro::TokenStream;
9use proc_macro2::TokenStream as TokenStream2;
10use quote::quote;
11use syn::{DeriveInput, parse_macro_input};
12
13use crate::{attr::Context, codegen::Codegen, input::Input, meta::Metadata};
14
15/// A `#[derive]` macro for larpa's `Command` trait.
16#[proc_macro_derive(Command, attributes(larpa))]
17pub fn derive_command(input: TokenStream) -> TokenStream {
18    let input = parse_macro_input!(input as DeriveInput);
19    let mut cx = Context::default();
20    match derive_command_impl(&mut cx, input) {
21        Ok(ts) => ts.into(),
22        Err(error) => {
23            let krate = cx.crate_path().unwrap_or_else(default_crate_path);
24            let private = quote!(#krate::private);
25            let mut attr_paths = TokenStream2::new();
26            cx.attr_refs(&private, |path| {
27                attr_paths.extend(quote!( let _ = #path; ));
28            });
29
30            let ide_helper = quote! {
31                const _: () = {
32                    #attr_paths
33                };
34            };
35
36            let error = error.to_compile_error();
37
38            quote! {
39                #ide_helper
40                #error
41            }
42            .into()
43        }
44    }
45}
46
47fn derive_command_impl(cx: &mut Context, input: DeriveInput) -> syn::Result<TokenStream2> {
48    let input = Input::parse(cx, &input)?;
49    let meta = Metadata::get();
50
51    let mut cg = Codegen::new(cx, &input, &meta);
52    cg.derive()
53}
54
55fn default_crate_path() -> syn::Path {
56    syn::parse_str("::larpa").unwrap()
57}