I'm writing a wrapper macro around the bitflags!
macro. (I think) I'm using a push-down accumulation and TT munching. Current source: Macro that wraps bitflags! from bitflags · GitHub
I'm invoking it as:
libc_bitflags!(
flags MsFlags: c_ulong {
MS_RDONLY,
}
);
but getting an error (with trace_macros!(true)
):
libc_bitflags! { flags MsFlags : c_ulong { MS_RDONLY , } }
libc_bitflags! { @ accumulate_flags MsFlags ; c_ulong ; ( ) ; ( ) ; MS_RDONLY , }
libc_bitflags! { @ accumulate_flags MsFlags ; c_ulong ; ( ) ; (
const MS_RDONLY = libc:: MS_RDONLY , ) ; }
src/macros.rs:57:58: 57:59 error: unexpected end of macro invocation
src/macros.rs:57 ($($flags)* const $flag = libc::$flag,); $($tail)*);
^
I'm confused by this. I've tried adding the semicolon in the patterns, removing it, surrounding the tail with parens and a whole bunch of other things. Am I trying to do something impossible, or just missing something?
I'm afraid I don't know what the problem is. See, because your macro code is so dense and just specifies everything by position, I found it impossible to read. So I rewrote it to be easier to understand... and accidentally fixed whatever the problem was.
*cough*
macro_rules! libc_bitflags {
// Exit rule.
(@call_bitflags
{
name: $BitFlags:ident,
type: $T:ty,
attrs: [$($attrs:tt)*],
flags: [$($flags:tt)*],
}
) => {
bitflags! {
$($attrs)*
flags $BitFlags: $T {
$($flags)*
}
}
};
// Done accumulating.
(@accumulate_flags
{
name: $BitFlags:ident,
type: $T:ty,
attrs: $attrs:tt,
},
$flags:tt;
) => {
libc_bitflags! {
@call_bitflags
{
name: $BitFlags,
type: $T,
attrs: $attrs,
flags: $flags,
}
}
};
// Munch an attr.
(@accumulate_flags
$prefix:tt,
[$($flags:tt)*];
#[$attr:meta] $($tail:tt)*
) => {
libc_bitflags! {
@accumulate_flags
$prefix,
[
$($flags)*
#[$attr]
];
$($tail)*
}
};
// Munch last ident if not followed by a comma.
(@accumulate_flags
$prefix:tt,
[$($flags:tt)*];
$flag:ident
) => {
libc_bitflags! {
@accumulate_flags
$prefix,
[
$($flags)*
const $flag = libc::$flag,
];
}
};
// Munch an ident; covers terminating comma case.
(@accumulate_flags
$prefix:tt,
[$($flags:tt)*];
$flag:ident, $($tail:tt)*
) => {
libc_bitflags! {
@accumulate_flags
$prefix,
[
$($flags)*
const $flag = libc::$flag,
];
$($tail)*
}
};
// Entry rules without `pub`.
(
$(#[$attr:meta])*
flags $BitFlags:ident: $T:ty {
$($vals:tt)*
}
) => {
libc_bitflags! {
@accumulate_flags
{
name: $BitFlags,
type: $T,
attrs: [$(#[$attr])*],
},
[];
$($vals)*
}
};
}
2 Likes
It was my first non-trivial macro following TLBORM, so that's not surprising!
That is significantly easier to read! And as you say, it works. Thanks!