Allow documenting of extern "Lua" functions
This commit is contained in:
parent
1aa9b4aa02
commit
122ef04b16
@ -6,6 +6,23 @@ use std::{
|
||||
hash::{Hash, Hasher},
|
||||
};
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
pub mod stub_types {
|
||||
pub struct any;
|
||||
pub struct nil;
|
||||
pub struct boolean;
|
||||
pub struct lightuserdata;
|
||||
pub struct number;
|
||||
pub struct integer;
|
||||
pub struct string;
|
||||
pub struct table;
|
||||
pub struct function;
|
||||
pub struct userdata;
|
||||
pub struct thread;
|
||||
pub struct cdata;
|
||||
pub struct variadic;
|
||||
}
|
||||
|
||||
pub fn type_id<T: 'static>() -> u64 {
|
||||
let mut hash = FxHasher::default();
|
||||
TypeId::of::<T>().hash(&mut hash);
|
||||
|
@ -202,10 +202,7 @@ fn get_ffi_functions(imp: &mut ItemImpl) -> Result<Vec<FfiFunction>> {
|
||||
{
|
||||
func.sig.abi = None;
|
||||
|
||||
// normalise inputs to PatType
|
||||
funcs.push(FfiFunction {
|
||||
name: func.sig.ident.clone(),
|
||||
params: func
|
||||
let params = func
|
||||
.sig
|
||||
.inputs
|
||||
.iter()
|
||||
@ -216,12 +213,21 @@ fn get_ffi_functions(imp: &mut ItemImpl) -> Result<Vec<FfiFunction>> {
|
||||
}
|
||||
FnArg::Typed(ty) => ty.clone(),
|
||||
})
|
||||
.collect(),
|
||||
ret: match func.sig.output {
|
||||
ReturnType::Default => parse_quote_spanned!(func.sig.span() => ()),
|
||||
.collect();
|
||||
|
||||
let ret = match func.sig.output {
|
||||
ReturnType::Default => parse_quote!(()),
|
||||
ReturnType::Type(_, ref ty) => (**ty).clone(),
|
||||
},
|
||||
attrs: parse_ffi_function_attrs(&mut func.attrs)?,
|
||||
};
|
||||
|
||||
let attrs = parse_ffi_function_attrs(&mut func.attrs)?;
|
||||
attrs.metamethod.map(|mm| document_metamethod(func, mm));
|
||||
|
||||
funcs.push(FfiFunction {
|
||||
name: func.sig.ident.clone(),
|
||||
params,
|
||||
ret,
|
||||
attrs,
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -339,13 +345,13 @@ fn add_ffi_function(registry: &mut FfiRegistry, func: &FfiFunction) -> Result<()
|
||||
|
||||
match get_ffi_param_type(func_param) {
|
||||
FfiParameterType::Default => {
|
||||
shim_params.push(quote_spanned!(param.span() =>
|
||||
shim_params.push(quote_spanned!(func_param.span() =>
|
||||
#shim_param: <#func_param as #ffi::FromFfi>::From
|
||||
));
|
||||
func_args.push(quote_spanned!(param.span() =>
|
||||
func_args.push(quote_spanned!(param.pat.span() =>
|
||||
<#func_param as #ffi::FromFfi>::convert(#shim_param)
|
||||
));
|
||||
build.push(quote_spanned!(param.span() =>
|
||||
build.push(quote_spanned!(param.pat.span() =>
|
||||
b.param::<#func_param>(#name);
|
||||
));
|
||||
}
|
||||
@ -432,15 +438,13 @@ struct LuaFunctionAttrs {
|
||||
|
||||
fn get_lua_functions(imp: &mut ItemImpl) -> Result<Vec<LuaFunction>> {
|
||||
let mut funcs = vec![];
|
||||
let mut i = 0;
|
||||
|
||||
while i < imp.items.len() {
|
||||
if let ImplItem::Fn(ref mut func) = imp.items[i]
|
||||
for item in imp.items.iter_mut() {
|
||||
if let ImplItem::Fn(func) = item
|
||||
&& let Some(ref abi) = func.sig.abi
|
||||
&& let Some(ref abi) = abi.name
|
||||
&& abi.value() == "Lua"
|
||||
{
|
||||
// normalise inputs to Pat
|
||||
let mut params: Vec<_> = func
|
||||
.sig
|
||||
.inputs
|
||||
@ -448,7 +452,6 @@ fn get_lua_functions(imp: &mut ItemImpl) -> Result<Vec<LuaFunction>> {
|
||||
.map(|arg| {
|
||||
Ok(match arg {
|
||||
FnArg::Receiver(recv) => {
|
||||
syn_assert!(ty_name(&recv.ty)? == "Self", recv, "must be `self`");
|
||||
syn_assert!(recv.mutability.is_none(), recv, "cannot be mut");
|
||||
Pat::Type(parse_quote_spanned!(recv.span() => self: cdata))
|
||||
}
|
||||
@ -461,29 +464,71 @@ fn get_lua_functions(imp: &mut ItemImpl) -> Result<Vec<LuaFunction>> {
|
||||
params.push(parse_quote_spanned!(variadic.span() => variadic!()));
|
||||
}
|
||||
|
||||
// shouldn't specify an output type
|
||||
syn_assert!(
|
||||
matches!(func.sig.output, ReturnType::Default),
|
||||
func.sig.output,
|
||||
"cannot have return type"
|
||||
);
|
||||
let attrs = parse_lua_function_attrs(&mut func.attrs)?;
|
||||
attrs.metamethod.map(|mm| document_metamethod(func, mm));
|
||||
|
||||
funcs.push(LuaFunction {
|
||||
name: func.sig.ident.clone(),
|
||||
params,
|
||||
body: func.block.clone(),
|
||||
attrs: parse_lua_function_attrs(&mut func.attrs)?,
|
||||
attrs,
|
||||
});
|
||||
|
||||
imp.items.remove(i);
|
||||
} else {
|
||||
i += 1;
|
||||
stub_lua_function(func)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(funcs)
|
||||
}
|
||||
|
||||
fn stub_lua_function(func: &mut ImplItemFn) -> Result<()> {
|
||||
// converts an extern "Lua" function into a regular function with no body to allow for
|
||||
// documentation generation
|
||||
let ffi = ffi_crate();
|
||||
|
||||
func.sig.abi = None;
|
||||
func.attrs.push(parse_quote!(#[allow(unused)]));
|
||||
func.block = parse_quote!({
|
||||
::std::unreachable!("cannot call lua function from rust");
|
||||
});
|
||||
|
||||
let inputs = &mut func.sig.inputs;
|
||||
for input in inputs.iter_mut() {
|
||||
if let FnArg::Typed(pat) = input {
|
||||
let span = pat.ty.span();
|
||||
let ty = if let Type::Infer(_) = *pat.ty {
|
||||
quote_spanned!(span => any)
|
||||
} else {
|
||||
match ty_name(&pat.ty)?.to_string().as_str() {
|
||||
"any" => quote_spanned!(span => any),
|
||||
"nil" => quote_spanned!(span => nil),
|
||||
"boolean" => quote_spanned!(span => boolean),
|
||||
"lightuserdata" => quote_spanned!(span => lightuserdata),
|
||||
"number" => quote_spanned!(span => number),
|
||||
"integer" => quote_spanned!(span => integer),
|
||||
"string" => quote_spanned!(span => string),
|
||||
"table" => quote_spanned!(span => table),
|
||||
"function" => quote_spanned!(span => function),
|
||||
"userdata" => quote_spanned!(span => userdata),
|
||||
"thread" => quote_spanned!(span => thread),
|
||||
"cdata" => quote_spanned!(span => cdata),
|
||||
_ => syn_error!(pat, "unknown lua type"),
|
||||
}
|
||||
};
|
||||
|
||||
pat.ty = Box::new(parse_quote!(#ffi::__internal::stub_types::#ty));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ref variadic) = func.sig.variadic {
|
||||
let ty = quote_spanned!(variadic.span() => variadic);
|
||||
inputs.push(parse_quote!(rest: #ffi::__internal::stub_types::#ty));
|
||||
func.sig.variadic = None;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_lua_function_attrs(attrs: &mut Vec<Attribute>) -> Result<LuaFunctionAttrs> {
|
||||
let mut parsed = LuaFunctionAttrs::default();
|
||||
let mut i = 0;
|
||||
@ -532,6 +577,36 @@ fn add_lua_function(registry: &mut LuaRegistry, func: &LuaFunction) -> Result<()
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn document_metamethod(func: &mut ImplItemFn, method: Metamethod) {
|
||||
let s = match method {
|
||||
Metamethod::Eq => "This is a metamethod which is called by the `==` operator.".into(),
|
||||
Metamethod::Len => "This is a metamethod which is called by the `#` operator.".into(),
|
||||
Metamethod::Lt => "This is a metamethod which is called by the `<` operator.".into(),
|
||||
Metamethod::Le => "This is a metamethod which is called by the `<=` operator.".into(),
|
||||
Metamethod::Concat => "This is a metamethod which is called by the `..` operator.".into(),
|
||||
Metamethod::Add => "This is a metamethod which is called by the `+` operator.".into(),
|
||||
Metamethod::Sub => "This is a metamethod which is called by the `-` operator.".into(),
|
||||
Metamethod::Mul => "This is a metamethod which is called by the `*` operator.".into(),
|
||||
Metamethod::Div => "This is a metamethod which is called by the `/` operator.".into(),
|
||||
Metamethod::Mod => "This is a metamethod which is called by the `%` operator.".into(),
|
||||
Metamethod::Pow => "This is a metamethod which is called by the `^` operator.".into(),
|
||||
Metamethod::Unm => "This is a metamethod which is called by the `-` operator.".into(),
|
||||
Metamethod::ToString => {
|
||||
"This is a metamethod which can be called by the `tostring` built-in function.".into()
|
||||
}
|
||||
Metamethod::Pairs => {
|
||||
"This is a metamethod which can be called by the `pairs` built-in function.".into()
|
||||
}
|
||||
Metamethod::Ipairs => {
|
||||
"This is a metamethod which can be called by the `ipairs` built-in function.".into()
|
||||
}
|
||||
_ => format!("This is a metamethod and cannot be called directly."),
|
||||
};
|
||||
|
||||
func.attrs.push(parse_quote!(#[doc = ""]));
|
||||
func.attrs.push(parse_quote!(#[doc = #s]));
|
||||
}
|
||||
|
||||
fn inject_fallback_new(registry: &mut LuaRegistry) -> Result<()> {
|
||||
let ty = ®istry.ty;
|
||||
let lua = format!(
|
||||
|
Loading…
x
Reference in New Issue
Block a user