3
非タプル引数をタプルに変換するマクロを作成できますか?非タプル引数をタプルに変換するマクロ
assert_eq!(tuplify!(1, (2, 3), 4), ((1,), (2, 3), (4,)));
このようなマクロを作成しようとしましたが、作成できませんでした。私が直面した問題は、それぞれの議論が2つの形式のうちの1つを持つことができ、それを特定する方法を理解できなかったことでした。
非タプル引数をタプルに変換するマクロを作成できますか?非タプル引数をタプルに変換するマクロ
assert_eq!(tuplify!(1, (2, 3), 4), ((1,), (2, 3), (4,)));
このようなマクロを作成しようとしましたが、作成できませんでした。私が直面した問題は、それぞれの議論が2つの形式のうちの1つを持つことができ、それを特定する方法を理解できなかったことでした。
マクロの各引数は、単一のトークン木である場合、これは行います:引数が複数のトークンのツリーを持っていることができれば何
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,)));
,
もトークンツリーとして解析することができますので、それがあいまいです。
これに取り組むために、私は "TT muncher"と書く必要があると思います。
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,)));
}
二度目に '@internal'と' @parse'を数日で見ると、私は狩りに行く必要があります。 –
私は[convention](https://danielkeep.github.io/tlborm/book/pat-internal-rules.html)にちょうど従っています。 :) –
リンクありがとう!それは巧妙なトリックです。 –