2021-09-09 16:50:58 -04:00
#[ macro_use ]
extern crate syn ;
#[ macro_use ]
extern crate quote ;
use proc_macro ::TokenStream ;
use quote ::ToTokens ;
2022-01-22 13:59:12 -05:00
use syn ::ItemFn ;
2021-09-09 16:50:58 -04:00
fn check_lua_function ( input : & mut ItemFn ) {
assert! ( input . sig . asyncness . is_none ( ) , " Cannot be async " ) ;
assert! ( input . sig . constness . is_none ( ) , " Cannot be const " ) ;
assert! ( input . sig . inputs . len ( ) = = 1 , " There can only be one argument, and it should be a pointer to the Lua state (gmod::lua::State) " ) ;
assert! ( input . sig . abi . is_none ( ) | | input . sig . abi . as_ref ( ) . and_then ( | abi | abi . name . as_ref ( ) ) . map ( | abi | abi . value ( ) = = " C-unwind " ) . unwrap_or ( true ) , " Do not specify an ABI " ) ;
input . sig . abi = Some ( syn ::parse_quote! ( extern " C-unwind " ) ) ;
}
2022-01-22 13:59:12 -05:00
fn genericify_return ( item_fn : & mut ItemFn ) {
let stmts = std ::mem ::take ( & mut item_fn . block . stmts ) ;
let output = std ::mem ::replace ( & mut item_fn . sig . output , parse_quote! ( -> i32 ) ) ;
item_fn . block . stmts = vec! [ syn ::parse2 ( quote! ( { ::gmod ::lua ::ValuesReturned ::from ( ( | | #output { #( #stmts ) ; * } ) ( ) ) . into ( ) } ) ) . unwrap ( ) ] ;
2021-12-09 14:32:56 -05:00
}
2021-09-09 16:50:58 -04:00
#[ proc_macro_attribute ]
pub fn gmod13_open ( _attr : TokenStream , tokens : TokenStream ) -> TokenStream {
let mut input = parse_macro_input! ( tokens as ItemFn ) ;
2022-01-22 13:59:12 -05:00
let lua_ident = format_ident! ( " {} " , match & input . sig . inputs [ 0 ] {
syn ::FnArg ::Typed ( arg ) = > arg . pat . to_token_stream ( ) . to_string ( ) ,
_ = > unreachable! ( ) ,
} ) ;
// Capture the Lua state
input . block . stmts . insert ( 0 , syn ::parse2 ( quote! ( ::gmod ::lua ::__set_state__internal ( #lua_ident ) ; ) ) . unwrap ( ) ) ;
// Load lua_shared
2021-10-21 10:05:01 -04:00
input . block . stmts . insert ( 0 , syn ::parse2 ( quote! ( #[ allow(unused_unsafe) ] unsafe { ::gmod ::lua ::load ( ) } ) ) . unwrap ( ) ) ;
2022-01-22 13:59:12 -05:00
// Make sure it's valid
check_lua_function ( & mut input ) ;
// No mangling
input . attrs . push ( parse_quote! ( #[ no_mangle ] ) ) ;
// Make the return type nice and dynamic
genericify_return ( & mut input ) ;
2021-12-09 13:23:19 -05:00
input . into_token_stream ( ) . into ( )
2021-09-09 16:50:58 -04:00
}
#[ proc_macro_attribute ]
pub fn gmod13_close ( _attr : TokenStream , tokens : TokenStream ) -> TokenStream {
let mut input = parse_macro_input! ( tokens as ItemFn ) ;
2022-01-22 13:59:12 -05:00
// Make sure it's valid
2021-09-09 16:50:58 -04:00
check_lua_function ( & mut input ) ;
2021-12-30 13:18:23 -05:00
2022-01-22 13:59:12 -05:00
// No mangling
input . attrs . push ( parse_quote! ( #[ no_mangle ] ) ) ;
// Shutdown gmcl thread if it's running
2021-12-30 13:18:23 -05:00
#[ cfg(feature = " gmcl " ) ] {
let stmts = std ::mem ::take ( & mut input . block . stmts ) ;
input . block . stmts = vec! [ syn ::parse2 ( quote! ( {
2022-01-04 16:56:01 -05:00
let ret = ( | | { #( #stmts ) ; * } ) ( ) ;
2021-12-30 13:18:23 -05:00
::gmod ::gmcl ::restore_stdout ( ) ;
ret
} ) ) . unwrap ( ) ] ;
}
2022-01-22 13:59:12 -05:00
// Make the return type nice and dynamic
genericify_return ( & mut input ) ;
2021-12-09 13:23:19 -05:00
input . into_token_stream ( ) . into ( )
2021-09-09 16:50:58 -04:00
}
#[ proc_macro_attribute ]
pub fn lua_function ( _attr : TokenStream , tokens : TokenStream ) -> TokenStream {
let mut input = parse_macro_input! ( tokens as ItemFn ) ;
2022-01-22 13:59:12 -05:00
// Make sure it's valid
2021-09-09 16:50:58 -04:00
check_lua_function ( & mut input ) ;
2022-01-22 13:59:12 -05:00
// Make the return type nice and dynamic
genericify_return ( & mut input ) ;
2021-12-09 13:23:19 -05:00
input . into_token_stream ( ) . into ( )
2021-09-09 16:50:58 -04:00
}