Macros 宏将非元组参数转换为元组

Macros 宏将非元组参数转换为元组,macros,rust,Macros,Rust,是否可以创建一个宏来将非元组参数转换为元组?我想要这样的东西: assert_eq!(tuplify!(1, (2, 3), 4), ((1,), (2, 3), (4,))); 我试图创建这样的宏,但无法做到这一点。我面临的问题是,每个参数可以有两种形式中的一种,而我不知道如何指定它。如果宏的每个参数都是一个标记树,那么这就可以: macro_rules! tuplify { (@inner ($($args:expr),*)) => (($($args,)*)); (

是否可以创建一个宏来将非元组参数转换为元组?我想要这样的东西:

assert_eq!(tuplify!(1, (2, 3), 4), ((1,), (2, 3), (4,)));

我试图创建这样的宏,但无法做到这一点。我面临的问题是,每个参数可以有两种形式中的一种,而我不知道如何指定它。

如果宏的每个参数都是一个标记树,那么这就可以:

macro_rules! tuplify {
    (@inner ($($args:expr),*)) => (($($args,)*));
    (@inner $arg:expr) => (($arg,));
    ($($arg:tt),*) => (($(tuplify!(@inner $arg),)*));
}
如果参数可以有多个标记树呢?例如:

assert_eq!(tuplify!(1 + 6, (2, 3), 4), ((7,), (2, 3), (4,)));
然后我们只需要接受一系列标记树,对吗

macro_rules! tuplify {
    (@inner ($($args:expr),*)) => (($($args,)*));
    (@inner $arg:expr) => (($arg,));
    ($($($arg_tt:tt)+),*) => (($(tuplify!(@inner $($arg)+),)*));
}
不,那太容易了:

<anon>:12:30: 12:31 error: local ambiguity: multiple parsing options: built-in NTs tt ('arg_tt') or 1 other option.
<anon>:12     assert_eq!(tuplify!(1 + 6, (2, 3), 4), ((7,), (2, 3), (4,)));

我第二次看到
@internal
@parse
的时候,我需要去跑步。我只是在遵循以下规则。:)
macro_rules! tuplify {
    (@as_expr $e:expr) => { $e };

    // No more tokens
    (@parse { } -> { $($current:tt)* } -> { $($output:tt)* }) => {
        tuplify!(@as_expr ( $($output)* ($($current)*,), ))
    };

    // Comma
    (@parse { , $($ts:tt)* } -> { $($current:tt)* } -> { $($output:tt)* }) => {
        tuplify!(@parse { $($ts)* } -> { } -> { $($output)* ($($current)*,), })
    };

    // Tuple followed by a comma, nothing in the current argument yet
    (@parse { ($($tuple_item:expr),*) , $($ts:tt)* } -> { } -> { $($output:tt)* }) => {
        tuplify!(@parse { $($ts)* } -> { } -> { $($output)* ($($tuple_item,)*), })
    };

    // Tuple followed by nothing else, nothing in the current argument yet
    (@parse { ($($tuple_item:expr),*) } -> { } -> { $($output:tt)* }) => {
        tuplify!(@parse { } -> { } -> { $($output)* ($($tuple_item,)*), })
    };

    // Base case
    (@parse { $t:tt $($ts:tt)* } -> { $($current:tt)* } -> { $($output:tt)* }) => {
        tuplify!(@parse { $($ts)* } -> { $t $($current)* } -> { $($output)* })
    };

    // Entry point
    ($($tokens:tt)*) => (tuplify!(@parse { $($tokens)* } -> { } -> { }));
}

fn main() {
    assert_eq!(tuplify!(1 + 6, (2, 3), 4), ((7,), (2, 3), (4,)));
}