labt_proc_macro/
lib.rs

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    // obtain the first argument
25    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        // less than two args specified, add an empty tuple since the user
48        // doesnt require args from lua
49        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![:](function.sig.inputs.span()),
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}