Macro 'no rules expected the token'

Hello,

I'm trying to play with macro and create a simple macro that create simple u32 flags.
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=191ce3ed423cad7717592c1f2be4d269
I have an error and I understand why, but I don't know how I can work around the problem.
My first attempt was to create a simple ident:literal pair. But it's flags so it can also be ident:expr.
How can I adjust this macro to allow this?

Thank you.

Hi, this is a solution by a simple mind person :sweat_smile::

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=3c9b3e1566cfb17587b6c1be2610866e

Well thank you but this is not an acceptable answer :smiley:

:smiley:

You want the content provided to the macro unmodified? Just fix the macro rules?

I want that the macro can accept a literal if we give a literal or a expr if we give an expr :slight_smile:
Line 3 $($field:ident= $value:literal,)+ just allow literal, but I want to accept literal or expr depending of what I give :slight_smile: the important is that literal is u32 and expr result is also u32.

A literal is an expr. Just use :expr.

(a literal can also be used as a pattern, in which case :expr would be no good; but you're not using it as a pattern here, so it doesn't matter)

I think this does what you want:

macro_rules! FLAGS {
    ( $name:ident{
        $($field:ident= $value:expr,)+
    }) => (
        #[derive(Copy, Clone, Eq, Ord, PartialEq, PartialOrd)]
        pub struct $name(u32);
        
        // limit scope of u32 consts
        const _: () = {
            // declare u32 constants all in one namespace so
            // that C = B | A "just works"
            $( const $field: u32 = $value; )+
            
            // wrap them with associated constants of the bitfield type
            impl $name {
                $(pub const $field: $name = $name($field);)+
            }
        };
        
        impl core::ops::BitOr for $name {
            type Output = Self;
            fn bitor(self, rhs: Self) -> Self {
                $name(self.0 | rhs.0)
            }
        }
    );
}

FLAGS!{
    SomeFlags {
        A = 0x00000000,
        B = 0x00000001,
        C = B | A,
    }
}
3 Likes

A big thank you! This is exactly what I need.
I don't understand what is the const _: () = {...} is this just the way to create a nested name space? With an unnamed constant?
There is no other way? using a constant to declare a impl works but the way to do it is pretty strange

Edit: Nevermind! I found the rfc for that :slight_smile: https://github.com/rust-lang/rfcs/pull/2526