English

マクロ

LuneScript のマクロは、コンパイル時にコード(AST)を展開・生成する強力な機能です。

定義

macro キーワードを使用して定義します。マクロ名は慣習としてアンダースコア _ で始めます。

macro _dprint( exp: __exp ) {
    print( "DEBUG:", ,,exp );
}

引数

マクロの引数には、通常の型の他に、マクロ専用の型を指定できます。

macro _assign( symbol: sym, val: int ) {
    ,,symbol = ,,val;
}
let mut val = 0;
_assign( val, 10 ); // val = 10; と展開される

Quoting (展開演算子)

マクロ本体(expand-statement)で引数を使用する場合、以下の演算子を使用して展開を制御します。

演算子 説明
,, 引数の値をそのままコードとして展開します。
,,, 引数の文字列値をシンボル名として展開します。
,,,, 引数のシンボル名を文字列リテラルに変換して展開します。
pub macro _hello( name: str ) {
    print( "Hello, ", ,,name );
}

Macro Statement

マクロ定義は、計算や準備を行う macro-statement(最初の {})と、実際にコードを生成する expand-statement(後半部分)で構成されます。

macro-statement 内では、LuneScript の標準的な計算機能が利用でき、動的に展開するコードの内容を決定できます。さらに `{} 演算子を使用することで、コードの断片(stat 型)を変数に格納してリスト化することも可能です。

動的なコード生成の例

以下の例では、指定された数だけ一連の変数を自動定義します。

macro _GenVars( prefix: str, count: int ) {
    {
        // macro-statement: 展開するコードのリストを作成
        let mut stats: List<stat> = [];
        for i = 1, count {
            let varName = "%s%d" (prefix, i);
            stats.insert( `{
                let ,,,"v_%s"(varName)~~ = ,,i;
            } );
        }
    }
    // expand-statement: 生成したリストを一気に展開
    ,,stats;
}

_GenVars( "val", 3 );
// let v_val1 = 1; let v_val2 = 2; let v_val3 = 3; と展開される
print( v_val1, v_val2, v_val3 ); // 1 2 3

macro-statement 内での制約

注意: Lua 予約語との衝突

マクロで展開されるコード内の変数名が Lua の予約語(end など)と衝突すると、トランスコンパイル後にエラーとなります。マクロ内部で使用する変数名には注意してください。
マクロは複雑な機能であり、乱用するとコードの可読性を損なう可能性があります。適切に使用してください。