2

I'm trying to make a macro to define some enum variants that represent assembler instructions.

Right now, I have the following which works fine. This is pretty useless, but eventually I'm going to add some automatically derived methods so it'll have a purpose later on:

macro_rules! define_instructions {
    ($($inames:tt),+ $(,)*) => {
        #[derive(Debug)]
        pub enum Instruction {
            $($inames),*
        }
    };
}

define_instructions! {
    PsqLux,
    PsqLx,
    Twi,
}

fn main() {}

The problem is that most (but not all) of the variants I'll be adding will need to have associated values:

define_instructions! {
    PsqLux(u32, u32, u32, u32, u32),
    PsqLx(u32, u32, u32, u32, u32),
    Twi(u32, u32, u32),
    SomethingWithoutAVariant,
}

I tried using this to allow for the variants to have associated values (it doesn't actually support associated values yet, it's just a start):

macro_rules! define_instructions {
    (@define) => {};

    (@define $iname:ident) => {
        $iname,
    };

    (@define $iname:ident $($inames:tt)*) => {
        $iname,
        define_instructions! { @define $($inames)* }
    };

    ($($inames:tt),+ $(,)*) => {
        #[derive(Debug)]
        pub enum Instruction {
            define_instructions! { @define $($inames)* }
        }
    };
}

define_instructions! {
    PsqLux,
    PsqLx,
    Twi,
}

That code gave me this error:

error: expected one of `(`, `,`, `=`, `{`, or `}`, found `!`
  --> src/main.rs:17:32
   |
17 |               define_instructions! { @define $($inames)* }
   |                                  ^ expected one of `(`, `,`, `=`, `{`, or `}` here
...
22 | / define_instructions! {
23 | |     PsqLux,
24 | |     PsqLx,
25 | |     Twi,
26 | | }
   | |_- in this macro invocation

It's seems like I can't use macros inside of an enum definition. Assuming that's true, how could I work around this and be able to generate enum variants that may or may not contain associated values?

Note: I'm sure there's something wrong with the rules I added, but I'd at least like to be able to get to the point where I can call them, so I can get them working.

Edit

mcarton explained another way to do what I'm trying to do, and that's helpful at the moment.

However I'd still like to know how to use a macro inside a enum definition, because in the future I'd be able to like to write macros like this:

define_instructions! {
    /// Name: Trap Word Immediate
    /// Simplified Mnemonics:
    /// twgti rA, value = twi 8, _rA, _value
    /// twllei rA, value = twi 6, _rA, _value
    twi TO, rA, SIMM;

    // and so on...  
}

// That macro would become

pub enum Instruction {
    /// Name: Trap Word Immediate
    /// Usage: twi TO, rA, SIMM
    /// Simplified Mnemonics:
    /// twi 8, rA, value = twgti rA, value
    /// twllei rA, value = twi 6, rA, value
    Twi(u32, u32, u32, u32, u32),
}

So I have the workaround, but I'm still curious if it's possible to use macros inside of an enum definition. Is that possible, and if not why isn't it?

Addison
  • 3,791
  • 3
  • 28
  • 48
  • 2
    What is your goal exactly? A simpler matcher such as `($($inames:tt)*) => { enum Instruction { $($inames)* } };` works fine, so my guess is you are trying to do something more with the variants, which it would be helpful to describe. – mcarton Aug 25 '18 at 20:01
  • Ah thanks, that helps with what I'm trying to do now. I didn't think to try that (this is my first macro in Rust so I'm still figuring of all this out). Although later on it may be helpful to have the macro in there for other stuff, so I'll update the question to include what that may be. – Addison Aug 25 '18 at 20:10
  • 1
    You want your macro to *modify your documentation comments*? – Shepmaster Aug 25 '18 at 20:24
  • I haven't really planned it out yet, that's probably a bad idea. I was just rushing to get an example on the question. The main point is that the enum variants are created from the documentation. I can remove the rest of the details to focus on that. – Addison Aug 25 '18 at 20:27
  • Additionally, you want to modify your `twi` to become `Twi`, and somehow intuit that the 3 values `TO, rA, SIMM` becomes 5 `u32`? It sounds like you are trying implement your actual assembler as a macro... – Shepmaster Aug 25 '18 at 20:27
  • @Shepmaster There's would also be custom `impl` stuff as well generated from the documentation, but I left that out as I didn't have an issue with that part. – Addison Aug 25 '18 at 20:28
  • I am writing an assembler (or rather attempting to haha). However I just wanted to define the possible instructions with macros so I could document the instructions' usages and generate a `impl` block from that for things like printing them out. Even if this isn't a good idea, I'd still love to know how to do this as I'm trying to learn more about Rust macros. – Addison Aug 25 '18 at 20:30
  • @Shepmaster And I didn't mean to sound like I don't appreciate advice on my approach to this, I really do appreciate it. My main concern right now is fixing this issue I have with this macro, but I'm also open to suggestions for what I should be doing instead if you explain why my approach isn't a good idea. It's just unclear what to do with your comments. – Addison Aug 25 '18 at 20:45
  • The problem I have with this question is that I have *no* idea what it is you want to do. You show 2.5 different styles of macro invocation; you show a before and after without explicitly stating what the transformation rules would be. Your original question was seemingly answered and yet all of the cruft from it remains, etc. The amount of effort this question requires from an answerer to know what you *want* is very high, and that's before they try to start *answering*. – Shepmaster Aug 25 '18 at 21:14
  • This leads to my questions, likely phrased poorly, all attempting to get you to clarify your question: *You want your macro to modify your documentation comments?* — is your question how to do this? *you want to modify your `twi` to become `Twi`* — is your question how to do this? *intuit that the 3 values TO, rA, SIMM becomes 5 u32* — is your question how to do this (we couldn't even begin to answer because the rules are opaque)? – Shepmaster Aug 25 '18 at 21:16
  • @Shepmaster I see your point. I had an "Edit" label for my response to mcarton that explained my goals, but I think that label got lost in the edits so now all that documentation stuff looks like part of my original question. I realize this is a bit of an xy problem, but in this case I really do want to know how to define the variants using a macro inside of the enum definition, even if it's not the ideal solution. I edited my question to try to make it more clear that I want to know if it's possible to do that, and that I'm not really concerned the the documentation stuff right now. – Addison Aug 25 '18 at 21:32
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/178760/discussion-between-shepmaster-and-addison). – Shepmaster Aug 25 '18 at 21:56

0 Answers0