I'm doing my first steps with macro_rule!
and would like to call my macro like this:
my_macro!(some_module::some_fkt)
The macro should create code like this:
fn some_fkt() {
some_module::some_fkt();
}
That's of course a simplified example, but the point is, that I need only the name for the function declaration, but the full path when calling it. I tried to match with $var:path
and to split the name from it, but found neither build in functionality nor was I able to do the split myself via an additional macro or so. So I probably have to solve it via a better matcher. The closest I could get is:
$($module:ident::)+$method:ident
If I match some_module::some_fkt
with this I get an error that the pattern is ambiguous. Same if I replace the +
with a *
, just with the error in a different place. I don't get that error, because the ::
needs to be mached and should make the match clear.
Is there an option to solve my problem with this kind of macro? Or do I have to go for a procedural one?
As a macros argument are parsed without looking ahead, this is a bit awkward to write, but it's possible:
macro_rules! my_macro {
($head:ident $(:: $tail:tt)+) => {
my_macro!( $head :: ; $($tail),* );
};
($($module:ident ::)+ ; $method:ident) => {
$($module ::)+ $method();
}
};
($($module:ident ::)+ ; $head:ident , $($tail:ident),+) => {
my_macro!( $($module ::)* $head :: ; $($tail),* );
};
}
The first clause just accepts the target syntax with separating by ::
and then hands off to the third clause which shifts the first parts of the path over to the bit before ;
one segment at a time, when only a single ident
is left to the right of ;
then the second clause applies and puts together the desired output.
Of course one could omit clauses one and three and just directly use that macro as my_macro!(some_module::;some_fkt)
, that is use a different separator for the last part, as well.