コード生成(パーサ)

この例では設定パーサをコンパイル時に生成します。 プログラムが2つの設定項目を持ち、それを下記のstructにまとめるとしましょう:

struct Config
{
    int runs, port;
    string name;
}

この構造体に対するパーサーを書くのは難しいことではないですが、 Configオブジェクトが変更されるたびにパーサーを更新しなければならないでしょう。 なので、任意の設定項目を読み込めるジェネリックなparse関数を書いてみたいです。 簡単のためにparsekey1=value1,key2=value2という非常に単純な書式の設定項目を受け付けることにしますが、 同様の手法が任意の設定フォーマットに利用できます。 もちろん多くの有名な設定フォーマットのためのリーダがDUBレジストリには存在します。

設定を読む

"name=dlang,port=8080"がユーザの設定文字列だとしましょう。 そして設定項目をコンマで分割し、各設定に対してparseを呼び出します。 すべての設定項目がパースされた後、設定オブジェクト全体が印字されます。

パース

parseで素敵な処理が実際に行われる場所ですが、まずは与えられた設定項目(例: "name=dlang") を"="でキー("name")と値("dlang")に分割します。 switch文はパースしたキーに対して実行されますが、興味深いのはswitch caseが静的に生成されることです。 c.tupleofはすべてのメンバのリストを(idx, name)という形式で返します。 コンパイラはc.tupleofがコンパイル時にわかることを検出し、コンパイル時にforeachループを展開します。 したがって、Conf.tupleof[idx].stringofは構造体オブジェクトの各メンバを返し、 各メンバに対してcase文を生成します。 同様に、静的ループの中では各メンバにc.tupleof[idx]のようにインデックスでアクセスできます。 なので、個々のメンバに設定文字列からパースした値を代入できます。 さらに、分割されたレンジはキーを指しているためdropOneが必要で、 dropOne.frontは2番めの要素を返します。 さらに、to!(typeof(field))は入力文字列の設定構造体のメンバの個々の型へのパースを行います。 最後に、foreachループはコンパイル時に展開されbreakがループを停止します。 しかし、設定項目がパースされた後にはswitch文の次のケースにジャンプしたくないため、 ラベル付されたbreakはswitch文の外に脱出するために使われます。

rdmd playground.d