I'm trying to write a macro that writes a function for me. Keep in mind that i have removed a lot of irrelevant details so i it may look a bit pointless. My macro looks like so:
macro_rules! command {
// Vars
(@vars, $var: ident: ?$type: ty, $($t:tt)*) => {
$var: Option<&$type>, command!(@vars, $($t)*)
};
(@vars, $var: ident: $type: ty, $($t:tt)*) => {
$var: &$type, command!(@vars, $($t)*)
};
(@vars, ) => {};
// Main
($name: ident ($($t:tt)*) $body: block) => {
fn $name(command!(@vars, $($t)*)) $body
};
}
And i invoke it like so:
command!(lol1_command(text: String, t: ?String,) {
println!("test")
});
This gives me an error. When i expand it using rust analyzer i get this which works
fn lol1_command(text: &String, t: Option<&String>) {
println!("cool");
}
The compile error i get is error: expected one of ':' or '|', found ')'
and it recommends me fn $name(_: command!(@ vars, text : String, t : ? String,)) $body
which to me looks like it does not expand command
recursively and insted thinks that the macro invokation is a parameter to the funktion. What is going on? I a'm quite confused. Thank in advance.
I have tried moving things around in the macro to try to move the function generation after the call the vars macro but to no avail.
The reference of declarative macros says:
Macros can expand to expressions, statements, items (including traits, impls, and foreign items), types, or patterns
Note that this list does not contain partial items such as a list of parameters, you can't produce that from a macro.
Instead of producing parts of the final function item you can pass those parts along and create a single, complete function item at the very end:
macro_rules! command {
// Vars
(
$name:ident,
$body:block,
@vars ($var:ident : ? $type:ty , $($v:tt)*)
@processed ($($p:tt)*)
) => {
command!{
$name,
$body,
@vars ($($v)*)
@processed ($($p)*, $var: Option<&$type>)
}
};
(
$name:ident,
$body:block,
@vars ($var:ident : $type:ty , $($v:tt)*)
@processed ($($p:tt)*)
) => {
command!{
$name,
$body,
@vars ($($v)*)
@processed ($($p)*, $var: &$type)
}
};
(
$name:ident,
$body:block,
@vars ()
@processed (,$($p:tt)*)
) => {
fn $name($($p)*) $body
};
// Main
($name:ident ($($t:tt)*) $body: block) => {
command!{$name, $body, @vars ($($t)*) @processed ()}
};
}