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#[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}