I'm trying to write a macro that does different things depending on a given type.
Here is what I'm doing now:
macro_rules! print_type {
(Option<Foo>) => {
println!("Option of Foo");
};
(Option<$return_type: ty>) => {
println!("Option of type");
};
($return_type: ty) => {
println!("simple type");
};
(
$return_type: ty;
$($rest: tt)*
) => {
print_type!($return_type);
print_type!($($rest)*);
};
}
fn main() {
// Expected output:
// Option of Foo
// simple type
// Option of type
print_type! {
Option<Foo>;
i32;
Option<(i32, String)>
}
}
For some reasons, only the last type seems to be matched correctly... Is there a way for each type to be correctly matched?
Thanks!
this recursion force the first captured meta variable to be parsed as ty
token, which will never match the explicit Option<...>
rules.
for example, the Option<Foo>
pattern consists of 4 tokens (leaf of tt
), namely:
ident(Option
);
LESS_THAN
operator;
ident(Foo
);
GREATER_THAN
operator;
OK, thank you! So I guess there's no way to do it other than this then?
macro_rules! print_type {
(Option<Foo>) => {
println!("Option of Foo");
};
(Option<$return_type: ty>) => {
println!("Option of type");
};
($return_type: ty) => {
println!("simple type");
};
}
fn main() {
// Expected output:
print_type!(Option<Foo>);
print_type!(i32);
print_type!(Option<(i32, String)>);
}
since you are expanding in statement context, you don't need "tail"-recursion, this should work:
macro_rules! print_type {
(Option<Foo> $(; $($tt:tt)*)?) => {
println!("Option of Foo");
$(print_type!($($tt)*))?
};
(Option<$return_type: ty> $(; $($tt:tt)*)?) => {
println!("Option of type");
$(print_type!($($tt)*))?
};
($return_type: ty $(; $($tt:tt)*)?) => {
println!("simple type");
$(print_type!($($tt)*))?
};
}
4 Likes
Yandros
November 24, 2024, 2:34pm
5
This last post is indeed the proper solution to this problem .
For more info, and/or for when the macro is too complex for repetition of the "munching" to be worth repeating in each branch, there is a helper crate and macro which lets you "unwrap" a :ty
capture (and other such high level captures) so that its tokens be inspectable again:
2 Likes