I'm trying to write a macro (stdlibfn) that turns a function within another function, into a block. For context, this is writing a little macro library to make it easier to create stdlib functions for my language - I have that working, now I want to automatically add them to the stdlib. For example, I'd write:
fn stdlib() -> Stdlib {
let fns : Vec<String, MyFunctionDeclaration> = vec![];
#[stdlibfn]
fn int__random__0() {
dint(rand::random());
}
fns.into_iter().collect()
}
and have that turn into:
fn stdlib() -> Stdlib {
let fns = vec![];
{
fn int__random__0() -> (String, MyFunctionDeclaration) {
// This bit works, so omitting
}
fns.push_back(int_random_0());
}
fns.into_iter().collect()
}
Note that this replaces an ItemFn with an ExprBlock, which syn doesn't seem to like. When I try to do this I get errors like "error: macro expansion ignores token { and any following", which implies to me that it doesn't like the idea of replacing an ItemFn with an ExprBlock? I've tried various other formulations of a similar sort, with no luck.
Here's my code:
#[proc_macro_attribute]
pub fn stdlibfn(_attr: TokenStream,
item: TokenStream)
-> TokenStream {
let input = syn::parse_macro_input!(item as syn::ItemFn);
// Note extra brace wrapper to make a block, 2 lines below
let fn_stmt: syn::Stmt = parse_quote! {
{
#[allow(non_snake_case)]
fn #fn_name() -> (String, MyfunctionDeclaration) {
// This bit works, so omitting
}
}
};
println!("{:?}", fn_stmt); // confirmed that this is parsed OK.
let insert_output: syn::Stmt = parse_quote! {
#fn_name();
};
println!("{:?}", insert_output); // This also parses fine.
let block = ExprBlock { attrs: vec![],
label: None,
block:
Block { stmts: vec![fn_stmt, insert_output],
brace_token: token::Brace { span: Span::call_site(), }, }, };
TokenStream::from(block.into_token_stream()) // this causes the error below
// TokenStream::from(fn_stmt.into_token_stream()) // if I remove the {} and use this, the function creation works fine.
and this is the error:
error: macro expansion ignores token `{` and any following
--> src/eval.rs:44:3
|
44 | #[stdlibfn]
| ^^^^^^^^^^^ caused by the macro expansion here
|
= note: the usage of `stdlibfn!` is likely invalid in item context
I don't have to return a block, but I want to find a way to turn it into some sort of list of statements so that I can add it to the Vec automatically.
I shouldn't be using an ItemFn, but syn doesn't appear to have another type to represent a function within a function, and an ItemFn parses fine in that context (it only fails when I try to return an ExprBlock).
Is there a way to accomplish this? Thanks!