Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

% 列挙型の解析

macro_rules! parse_unitary_variants {
    (@as_expr $e:expr) => {$e};
    (@as_item $($i:item)+) => {$($i)+};
    
    // 終了ルール。
    (
        @collect_unitary_variants ($callback:ident ( $($args:tt)* )),
        ($(,)*) -> ($($var_names:ident,)*)
    ) => {
        parse_unitary_variants! {
            @as_expr
            $callback!{ $($args)* ($($var_names),*) }
        }
    };

    (
        @collect_unitary_variants ($callback:ident { $($args:tt)* }),
        ($(,)*) -> ($($var_names:ident,)*)
    ) => {
        parse_unitary_variants! {
            @as_item
            $callback!{ $($args)* ($($var_names),*) }
        }
    };

    // 属性を消費する。
    (
        @collect_unitary_variants $fixed:tt,
        (#[$_attr:meta] $($tail:tt)*) -> ($($var_names:tt)*)
    ) => {
        parse_unitary_variants! {
            @collect_unitary_variants $fixed,
            ($($tail)*) -> ($($var_names)*)
        }
    };

    // 必要に応じて初期化子付きのバリアントを処理する。
    (
        @collect_unitary_variants $fixed:tt,
        ($var:ident $(= $_val:expr)*, $($tail:tt)*) -> ($($var_names:tt)*)
    ) => {
        parse_unitary_variants! {
            @collect_unitary_variants $fixed,
            ($($tail)*) -> ($($var_names)* $var,)
        }
    };

    // ペイロードを持つバリアントで中止する。
    (
        @collect_unitary_variants $fixed:tt,
        ($var:ident $_struct:tt, $($tail:tt)*) -> ($($var_names:tt)*)
    ) => {
        const _error: () = "非単位バリアントを含む enum から単位バリアントを解析できません";
    };
    
    // エントリルール。
    (enum $name:ident {$($body:tt)*} => $callback:ident $arg:tt) => {
        parse_unitary_variants! {
            @collect_unitary_variants
            ($callback $arg), ($($body)*,) -> ()
        }
    };
}

fn main() {
    assert_eq!(
        parse_unitary_variants!(
            enum Dummy { A, B, C }
            => stringify(variants:)
        ),
        "variants : ( A , B , C )"
    );
}

このマクロは、インクリメンタル tt muncherプッシュダウン蓄積 を使用して、すべてのバリアントが単位バリアント(すなわち、ペイロードを持たない)である enum のバリアントを解析する方法を示しています。完了すると、parse_unitary_variants! はバリアントのリスト(および指定されたその他の任意の引数)を指定して コールバック マクロを呼び出します。

これは、struct フィールドの解析、バリアントのタグ値の計算、さらには任意の enum に含まれる すべての バリアント名の抽出も行えるように変更できます。