% インクリメンタル TT muncher
macro_rules! mixed_rules { () => {}; (trace $name:ident; $($tail:tt)*) => { { println!(concat!(stringify!($name), " = {:?}"), $name); mixed_rules!($($tail)*); } }; (trace $name:ident = $init:expr; $($tail:tt)*) => { { let $name = $init; println!(concat!(stringify!($name), " = {:?}"), $name); mixed_rules!($($tail)*); } }; } fn main() { let a = 42; let b = "Ho-dee-oh-di-oh-di-oh!"; let c = (false, 2, 'c'); mixed_rules!( trace a; trace b; trace c; trace b = "They took her where they put the crazies."; trace b; ); }
このパターンは、おそらく利用可能なマクロのパース手法の中で最も強力なもので、かなり複雑な文法をパースできます。
「TT muncher」とは、入力を1ステップずつインクリメンタルに処理することで動作する再帰的なマクロです。各ステップで、入力の先頭からトークン列の一部にマッチしてそれを削除(munch)し、中間出力を生成してから、入力の残りに対して再帰します。
名前に特に「TT」が含まれる理由は、入力の未処理部分が常に $($tail:tt)* としてキャプチャされるからです。これを行うのは、tt の繰り返しが、マクロ入力の一部を損失なくキャプチャする唯一の方法だからです。
TT muncher に対する厳格な制約は、マクロシステム全体に課されているものだけです。
- リテラル、および
macro_rules!でキャプチャ可能な文法構成要素に対してしかマッチできません。 - バランスの取れていないグループにはマッチできません。
ただし、マクロの再帰制限を念頭に置くことは重要です。macro_rules! には、末尾再帰除去や最適化の形式が一切ありません。TT muncher を書くときは、再帰をできるだけ抑えるために妥当な努力をすることが推奨されます。これは、(中間層へ再帰するのではなく)入力のバリエーションに対応する追加のルールを加えるか、標準の繰り返しをより扱いやすくするために入力構文について妥協することで実現できます。