§5.メタ記述の限界




まず、構文を定義するための構文を考えてみよう。構文を定義するための構文と、そこで使う基本的な命令。これらはどうしても欠かすことが出来ない。

次のような5回まわる構文を考えてみよう。

枠-1
    5.loop {
        //  文
    }


整数に対して作用させてあるので、loopはintegerクラスのメンバとして定義される。ただし、関数という概念ではない。integerクラスが保有しているマクロ、とぐらいに考えれば良い。そこで、このようなマクロは一箇所に固めて定義するのではなく、ファイルに分散して定義されていても構わないという仕様でなければならない。C++のnamespace的だと言っておこう。MixJuiceの差分モジュールという考えかたもこれに根ざすものだ。

上記のloopを定義するために、やねうらおは次のような構文で定義できれば良いと考える。

枠-2
class integer {
    def loop s:statement {
        for(int i=0;i<*this;++i){ s; }
    }
}


ご覧の通り、数字はintegerクラスに属すとみなされコンパイルされる。また、ここで出てくるstatementとは型名扱いである。

このコードは、別段難しくない。そのまま、マクロが展開されて埋め込まれると考えれば良いだろう。

C#のfor_eachも実装してみよう。

枠-3
class grobal {  //  グローバル空間に存在すると考えられるクラス
    foreach "(" it:iterator "in" e:IEnumerable ")" s:statement {
    //          ↑呼び出しは、パターンマッチングによって行なわれる
        it = e.begin();
        while (it!=e.end()){
            s(it);
            it++;
        }
    }


まあ、このへんは別段難しくないのだが、メタ記述の限界については少し述べておかなければならない。

n回まわるプログラムをループ変数を用いずに、n回その処理を書く(展開する)ことも可能だろう。指定された回数だけ処理を展開するには、どうすれば良いのだろうか?

..これを書くには、プリプロセッサが実行フェイズ(コマンドを実行する能力)を持たなければならない。欲を言えば、この言語の記述力と同じだけの記述力を持った言語でプリプロセッサに対して指令を出したい。

これは簡単なようでそう簡単ではない。この言語の場合、ソースコードはC++のソースコードを生成することになっている。プリプロセッサが実行フェイズを持つためには、C++のコードを生成せずに、実行する能力を持たなければならないことになる。すなわち、インタプリタ的に実行できなければならないことになる。

ネイティブコード生成が面倒だから、C++のコードを生成しているのに、なんだか本末転倒ぎみである。

そんなわけで、そのへんは気が向いたらということにする。