是否可以创建一个宏来将非元组参数转换为元组?我想要这样的东西:
assert_eq!(tuplify!(1, (2, 3), 4), ((1,), (2, 3), (4,)));
我试图创建这样的宏但无法这样做。我遇到的问题是每个参数可以有两种形式中的一种,我无法弄清楚如何指定它。
答案 0 :(得分:5)
如果宏的每个参数都是单个标记树,那么这将执行:
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,)));
这是不明确的,因为,
也可以解析为令牌树。
为了解决这个问题,我认为我们需要写一个&#34; TT muncher&#34;。
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,)));
}