1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{
4 parse_macro_input, punctuated::Punctuated, spanned::Spanned, token::Paren, FnArg, Item,
5 PatTuple, PatType, Token, TypeTuple,
6};
7extern crate proc_macro;
8
9#[proc_macro_attribute]
10pub fn labt_lua(_attr: TokenStream, item: TokenStream) -> TokenStream {
11 let mut function = match parse_macro_input!(item as Item) {
12 Item::Fn(item) => item,
13 _ => panic!("This attribute is only applicable to functions"),
14 };
15
16 let name = &function.sig.ident;
17
18 let sig = &function.sig;
19
20 let function_visibility = &function.vis;
21 let block = &function.block;
22 let function_return = &function.sig.output;
23
24 if let Some(first) = sig.inputs.first() {
26 match first {
27 FnArg::Typed(arg) => arg,
28 _ => {
29 return syn::Error::new(
30 first.span(),
31 "Only functions are allowed, methods are not supported",
32 )
33 .to_compile_error()
34 .into()
35 }
36 }
37 } else {
38 return syn::Error::new(
39 name.span(),
40 "Incorrect function signature, at least the Lua context is required! as the first argument",
41 )
42 .to_compile_error()
43 .into();
44 };
45
46 if function.sig.inputs.len() < 2 {
47 function.sig.inputs.push(FnArg::Typed(PatType {
50 pat: Box::new(syn::Pat::Tuple(PatTuple {
51 attrs: vec![],
52 paren_token: Paren::default(),
53 elems: Punctuated::new(),
54 })),
55 ty: Box::new(syn::Type::Tuple(TypeTuple {
56 paren_token: Paren::default(),
57 elems: Punctuated::new(),
58 })),
59 attrs: vec![],
60 colon_token: Token),
61 }));
62 }
63 let params = &function.sig.inputs;
64
65 let output: TokenStream = quote! {
66 #function_visibility fn #name(lua: &mlua::Lua, table: &mlua::Table) -> mlua::Result<()> {
67 let function = lua.create_function(move |#params| #function_return
68 #block
69 )?;
70
71 table.set(stringify!(#name), function)?;
72 Ok(())
73 }
74 }
75 .into();
76
77 output
78}