use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, spanned::Spanned, DeriveInput};
mod attrs;
mod custom_type;
mod function;
mod module;
mod register;
mod rhai_module;
#[cfg(test)]
mod test;
#[proc_macro_attribute]
pub fn export_module(args: TokenStream, input: TokenStream) -> TokenStream {
let parsed_params = match crate::attrs::outer_item_attributes(args.into(), "export_module") {
Ok(args) => args,
Err(err) => return err.to_compile_error().into(),
};
let mut module_def = parse_macro_input!(input as module::Module);
if let Err(e) = module_def.set_params(parsed_params) {
return e.to_compile_error().into();
}
let tokens = module_def.generate();
TokenStream::from(tokens)
}
#[proc_macro]
pub fn exported_module(module_path: TokenStream) -> TokenStream {
let module_path = parse_macro_input!(module_path as syn::Path);
TokenStream::from(quote::quote! {
#module_path::rhai_module_generate()
})
}
#[proc_macro]
pub fn combine_with_exported_module(args: TokenStream) -> TokenStream {
match crate::register::parse_register_macro(args) {
Ok((module_expr, _export_name, module_path)) => TokenStream::from(quote! {
#module_path::rhai_generate_into_module(#module_expr, true)
}),
Err(e) => e.to_compile_error().into(),
}
}
#[deprecated(since = "1.18.0")]
#[proc_macro_attribute]
pub fn export_fn(args: TokenStream, input: TokenStream) -> TokenStream {
let mut output = quote! {
#[allow(clippy::needless_pass_by_value)]
};
output.extend(proc_macro2::TokenStream::from(input.clone()));
let parsed_params = match crate::attrs::outer_item_attributes(args.into(), "export_fn") {
Ok(args) => args,
Err(err) => return err.to_compile_error().into(),
};
let mut function_def = parse_macro_input!(input as function::ExportedFn);
if !function_def.cfg_attrs().is_empty() {
return syn::Error::new(
function_def.cfg_attrs()[0].span(),
"`cfg` attributes are not allowed for `export_fn`",
)
.to_compile_error()
.into();
}
if let Err(e) = function_def.set_params(parsed_params) {
return e.to_compile_error().into();
}
output.extend(function_def.generate());
TokenStream::from(output)
}
#[deprecated(since = "1.18.0")]
#[proc_macro]
pub fn register_exported_fn(args: TokenStream) -> TokenStream {
match crate::register::parse_register_macro(args) {
Ok((engine_expr, export_name, rust_mod_path)) => {
let gen_mod_path = crate::register::generated_module_path(&rust_mod_path);
TokenStream::from(quote! {
#engine_expr.register_fn(#export_name, #gen_mod_path::dynamic_result_fn)
})
}
Err(e) => e.to_compile_error().into(),
}
}
#[deprecated(since = "1.18.0")]
#[proc_macro]
pub fn set_exported_fn(args: TokenStream) -> TokenStream {
match crate::register::parse_register_macro(args) {
Ok((module_expr, export_name, rust_mod_path)) => {
let gen_mod_path = crate::register::generated_module_path(&rust_mod_path);
let mut tokens = quote! {
let fx = FuncRegistration::new(#export_name).with_namespace(FnNamespace::Internal)
};
#[cfg(feature = "metadata")]
tokens.extend(quote! {
.with_params_info(#gen_mod_path::Token::PARAM_NAMES)
});
tokens.extend(quote! {
;
#module_expr.set_fn_raw_with_options(fx, &#gen_mod_path::Token::param_types(), #gen_mod_path::Token().into());
});
tokens.into()
}
Err(e) => e.to_compile_error().into(),
}
}
#[deprecated(since = "1.18.0")]
#[proc_macro]
pub fn set_exported_global_fn(args: TokenStream) -> TokenStream {
match crate::register::parse_register_macro(args) {
Ok((module_expr, export_name, rust_mod_path)) => {
let gen_mod_path = crate::register::generated_module_path(&rust_mod_path);
let mut tokens = quote! {
let fx = FuncRegistration::new(#export_name).with_namespace(FnNamespace::Global)
};
#[cfg(feature = "metadata")]
tokens.extend(quote! {
.with_params_info(#gen_mod_path::Token::PARAM_NAMES)
});
tokens.extend(quote! {
;
#module_expr.set_fn_raw_with_options(fx, &#gen_mod_path::Token::param_types(), #gen_mod_path::Token().into());
});
tokens.into()
}
Err(e) => e.to_compile_error().into(),
}
}
#[proc_macro_derive(CustomType, attributes(rhai_type,))]
pub fn derive_custom_type(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let expanded = custom_type::derive_custom_type_impl(input);
expanded.into()
}
#[proc_macro_attribute]
pub fn expose_under_internals(args: TokenStream, input: TokenStream) -> TokenStream {
let args: proc_macro2::TokenStream = args.into();
let input: proc_macro2::TokenStream = input.into();
if !args.is_empty() {
return syn::Error::new(
args.span(),
"`expose_under_internals` cannot have arguments.",
)
.to_compile_error()
.into();
}
if let Ok(mut item) = syn::parse2::<syn::ItemFn>(input.clone()) {
match item.vis {
syn::Visibility::Inherited => (),
_ => {
return syn::Error::new(
item.vis.span(),
"Function with `expose_under_internals` must not have any visibility.",
)
.to_compile_error()
.into();
}
}
item.vis = syn::parse2(quote! { pub }).unwrap();
let mut result = quote! {
#[cfg(feature = "internals")]
#item
};
item.vis = syn::parse2(quote! { pub(crate) }).unwrap();
result.extend(quote! {
#[cfg(not(feature = "internals"))]
#item
});
return result.into();
}
if let Ok(mut item) = syn::parse2::<syn::ItemType>(input.clone()) {
match item.vis {
syn::Visibility::Inherited => (),
_ => {
return syn::Error::new(
item.vis.span(),
"`type` definitions with `expose_under_internals` must not have any visibility.",
)
.to_compile_error()
.into();
}
}
item.vis = syn::parse2(quote! { pub }).unwrap();
let mut result = quote! {
#[cfg(feature = "internals")]
#item
};
item.vis = syn::parse2(quote! { pub(crate) }).unwrap();
result.extend(quote! {
#[cfg(not(feature = "internals"))]
#item
});
return result.into();
}
if let Ok(mut item) = syn::parse2::<syn::ItemUse>(input.clone()) {
match item.vis {
syn::Visibility::Inherited => (),
_ => {
return syn::Error::new(
item.vis.span(),
"`use` statements with `expose_under_internals` must not have any visibility.",
)
.to_compile_error()
.into();
}
}
item.vis = syn::parse2(quote! { pub }).unwrap();
let mut result = quote! {
#[cfg(feature = "internals")]
#item
};
item.vis = syn::parse2(quote! { pub(crate) }).unwrap();
result.extend(quote! {
#[cfg(not(feature = "internals"))]
#item
});
return result.into();
}
syn::Error::new(input.span(), "Cannot use `expose_under_internals` here.")
.to_compile_error()
.into()
}