スポンサーリンク

Rustの手続き的マクロを考える(1)トークンストリームを確認してみる

Rustには、「宣言的マクロ」(macro_rules!で定義する)と「手続き的マクロ」があり、「手続き的マクロ」にはさらにderiveマクロ、関数風マクロ、属性風マクロという分類がある。

手続き型マクロの原理

手続き型マクロは、マクロの呼び出し元から入ってきたコード片を「トークンストリーム」として受け取る。PGはこのトークンストリームを処理することでマクロに与えられたコードをコンパイル時に書き換えることができる。

マクロを作る前に、トークンストリームを表示してみる。

手続き型マクロの作り方

手続き型マクロは、専用のクレートを作らなければいけない。

今回は、main関数があるほうをmymain、マクロを定義する法をmymacroとしてクレートを作成する。

cargo new --lib mymacro
cargo new mymain

 

mymacroクレート

Cargo.toml

Cargo.tomlに以下を記述する。

[lib]
proc-macro = true

lib.rs

extern crate proc_macro;

use proc_macro::TokenStream;

#[proc_macro]
pub fn print_tokens(input: TokenStream) -> TokenStream {
    // TokenStreamをStringに変換
    let input_str = input.to_string();

    // 画面に表示
    println!("Received TokenStream: {}", input_str);

    
    // inputを一つ一つのTokenに分割
    for tk in input.clone().into_iter() {                

        // 画面に表示
        println!("*** {}", tk);
    };


    // 入力をそのまま返す(または他のTokenStreamを返す)
    input
}

mymainクレート

Cargo.toml

以下のdependenciesを追加。

[dependencies]
mymacro = { path = "../mymacro" }

main.rs

extern crate mymacro;


fn main() {

    let mut value=5;
    
    mymacro::print_tokens! {

        value = value + 5;

    }

    print!("hello world {} ",value);
}

build

mymainをbuildする。

\mymain>cargo build

すると、ビルド時に以下のようにトークンストリームが表示される(実行時ではない)。

Compiling mymain v0.1.0 (D:\test\mymain)
Received TokenStream: value = value + 5 ;
*** value
*** =
*** value
*** +
*** 5
*** ;
Finished dev [unoptimized + debuginfo] target(s) in 0.32s

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


この記事のトラックバックURL: