Macro problem in enum

I don't understand why this doesn't work properly? Or do I have to write them all by hand? I'm trying to write a toy RISC V VM, but I feel that the way to process the instructions is too complicated (and the RISC V instruction set itself has a relatively fixed structure).

Syntax Error: expected COMMArust-analyzersyntax-error
Syntax Error: expected enum variantrust-analyzersyntax-error
Syntax Error: expected COMMArust-analyzersyntax-error
Syntax Error: expected enum variantrust-analyzersyntax-error
Syntax Error: expected COMMArust-analyzersyntax-error
macro_rules! r_type {
    ( $( $name:ident ),* ) => {
        $(
            #[doc = concat!("Rεž‹ζŒ‡δ»€: ", stringify!($name))]
            $name {
                rd: String,
                rs1: String,
                rs2: String,
            },
        )*
    };
}

macro_rules! i_type {
    ( $( $name:ident ),* ) => {
        $(
            #[doc = concat!("Iεž‹ζŒ‡δ»€: ", stringify!($name))]
            $name {
                rd: String,
                rs1: String,
                rs2: i64,
            },
        )*
    };
}

macro_rules! u_type {
    ( $( $name:ident ),* ) => {
        $(
            #[doc = concat!("Uεž‹ζŒ‡δ»€: ", stringify!($name))]
            $name {
                rd: String,
                rs1: i64,
            },
        )*
    };
}
enum Instruction {
    // R εž‹
    r_type!(ADD, SUB, SLT, SLTU, AND, OR, XOR, SLL, SRL, SRA, MUL);

    // I εž‹
    i_type!(ADDI, SLTI, SLTIU, ANDI, ORI, XORI, SLLI, SRLI, SRAI);

    // U εž‹
    u_type!(LUI, AUIPC);

    // δΌͺζŒ‡δ»€
    SEQZ { rd: String, rs1: String },
    NOP,
    MV { rd: String, rs1: String },
    NOT { rd: String, rs1: String },
    Li { rd: String, rs1: i64 },
}

an enum variant is not a valid position for a macro invocation. valid positions includes: expressions, statements, patterns, types, items.

1 Like

So I have no choice but to write them one by one by hand? :confounded_face: ok, alright ...

Trying this code in the playground I get the following:

error: unexpected token: `!`
  --> src/lib.rs:40:11
   |
40 |     r_type!(ADD, SUB, SLT, SLTU, AND, OR, XOR, SLL, SRL, SRA, MUL);
   |           ^ unexpected token after this
   |
   = note: macros cannot expand to enum variants

Why not create structs to represent the common data, like this:

struct RTypeData {
    rd: String,
    rs1: String,
    rs2: String
}

struct ITypeData {
    rd: String,
    rs1: String,
    rs2: i64
}

struct UTypeData {
    rd: String,
    rs1: i64
}

enum Instruction {
    // R εž‹
    /// Rεž‹ζŒ‡δ»€: ADD
    ADD(RTypeData),
    /// Rεž‹ζŒ‡δ»€: SUB
    SUB(RTypeData),
    /// Rεž‹ζŒ‡δ»€: SLT
    SLT(RTypeData),
    /// Rεž‹ζŒ‡δ»€: SLTU
    SLTU(RTypeData),
    /// Rεž‹ζŒ‡δ»€: AND
    AND(RTypeData),
    /// Rεž‹ζŒ‡δ»€: OR
    OR(RTypeData),
    /// Rεž‹ζŒ‡δ»€: XOR
    XOR(RTypeData),
    /// Rεž‹ζŒ‡δ»€: SLL
    SLL(RTypeData),
    /// Rεž‹ζŒ‡δ»€: SRL
    SRL(RTypeData),
    /// Rεž‹ζŒ‡δ»€: SRA
    SRA(RTypeData),
    /// Rεž‹ζŒ‡δ»€: MUL
    MUL(RTypeData),

    // I εž‹
    /// Iεž‹ζŒ‡δ»€: ADDI
    ADDI(ITypeData),
    /// Iεž‹ζŒ‡δ»€: SLTI
    SLTI(ITypeData),
    /// Iεž‹ζŒ‡δ»€: SLTIU
    SLTIU(ITypeData),
    /// Iεž‹ζŒ‡δ»€: ANDI
    ANDI(ITypeData),
    /// Iεž‹ζŒ‡δ»€: ORI
    ORI(ITypeData),
    /// Iεž‹ζŒ‡δ»€: XORI
    XORI(ITypeData),
    /// Iεž‹ζŒ‡δ»€: SLLI
    SLLI(ITypeData),
    /// Iεž‹ζŒ‡δ»€: SRLI
    SRLI(ITypeData),
    /// Iεž‹ζŒ‡δ»€: SRAI
    SRAI(ITypeData),
    
    // U εž‹
    /// Uεž‹ζŒ‡δ»€: LUI
    LUI(UTypeData),
    /// Uεž‹ζŒ‡δ»€: AUIPC
    AUIPC(UTypeData),

    // δΌͺζŒ‡δ»€
    SEQZ { rd: String, rs1: String },
    NOP,
    MV { rd: String, rs1: String },
    NOT { rd: String, rs1: String },
    Li { rd: String, rs1: i64 },
}

Playground: Rust Playground

2 Likes

Indeed, it seems like a good choice. :grinning_face:

it depends on how crazy you want to go with macros, how robust you want the parsing to be, and also how well the the syntax was designed for the custom DSL.

use the Tools button then Expand Macros to see the expanded code:

4 Likes

Damn, this is the craziest and most powerful macro writing method I have ever seen.I can't express my shock, but I admire you.

Additional supplement, because my demand code is basically similar to this structure.

pub enum Instruction {}

impl Instruction {}

mod test {}

I think this is very unified. This framework is so unified. I think your solution is the best, you can use multiple small macros to splice into a large macro. Thank you very much for your inspiration.

The last information supplement, according to nerditationInspired by this, I finally got the solution. I'll share it with you for your reference (in case anyone is interested? Whatever)

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.