dtolnay/paste

macro expansion fails with formating types inside a string literal

Xephobia opened this issue · 4 comments

regarding this code :

use paste::paste;
use serenity::{
    framework::standard::{macros::command, CommandResult},
    model::prelude::*,
    prelude::*,
};

macro_rules! gen_random_funs {
    [$($x:ty),*] => {
        paste! {
        $(
            #[command("`"$x"`")]
            #[description = "generates a random `" $x "`"]
            async fn [<_ $x>](ctx: &Context, msg: &Message) -> CommandResult {
                msg.reply(ctx, rand::random::<$x>()).await?;
                Ok(())
            }

        )*
    }
    };
}

gen_random_funs![u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, f32, f64];

this fails with all the argument, quote unexpected token, note that macro also fail to expand in attributes in paste! blocks, this prevents the use of stringify! and such.

The #[command(""$x"")] bit fails because it put space around the expr, I don't know if it is really the issue, but it is unintended

You could do it like this:

macro_rules! gen_random_funs {
    ($($x:ty),*) => {
        $(
            paste!(gen_random_funs! {
                #[command = "" $x]
                #[description = "generates a random `" $x "`"]
                async fn [<_ $x>](ctx: &Context, msg: &Message) -> CommandResult {
                    msg.reply(ctx, rand::random::<$x>()).await?;
                    Ok(())
                }
            });
        )*
    };
    (#[command = $command:literal] $fn:item) => {
        #[command($command)]
        $fn
    };
}

This works, thanks! We should leave the issue open until there is a fix for the og code.

I think there doesn't need to be any change made in paste. #[attr("..." $x "...")] is already a syntactically valid attribute so it doesn't make sense for paste to mess with it. #[attr = "..." $x "..."] is syntactically invalid so that's the signal for paste to apply the concatenation of the strings into a single literal.