組み込み特殊変数の扱い

今日は変数の扱いを考えていて、やっぱり進んでいません。


bjamには$(1)や$(<)などの特殊な変数がありますが、この扱いはちょっと特殊です。

rule test1 ( * )
{
    1 = hogehoge ;
    if $(1) != hogehoge
    {
        ECHO oops! ; # ここが実行される!
    }
}

test1 arg1 ;

$(1)はルールの第一引数にアクセスする変数で、その名前で代入できるものの、読み出すと元の値が返されます。
この仕様を忠実に再現しつつ変数の展開処理を実装しようとすると、変数テーブルとは別にルールの引数まで必要になり、単体でのテストがやり辛くなります。


実際問題、読み出せない変数に書き込むことはないので、特殊変数も普通に変数テーブルに入れてしまおうと思ったのですが、

import path ;
rule test2 ( * )
{
    ECHO $(1) ; # 「arg1」を出力
    module path
    {
        ECHO $(1) ; # 「arg1」を出力
    }
}
test2 arg1 ;

のように、特殊変数はモジュールに依存しないため、変数テーブルに入れるわけにはいかないようです。
拡張性やテストの単純化のため、なるべく単機能に分離しようと考えていたのですが、bjamの仕様上難しそうです。


あと、変数展開にもバグを見つけました。
var_expand_grammarは変数展開のオプションを前から順に処理していましたが、

ECHO $(:E=hoge.txt:S) ; # 「.txt」を出力
ECHO $(:SE=hoge.txt) ; # 「.txt」を出力

ECHO $(:E=Ul:UL) ; # 「UL」を出力
ECHO $(:E=lU:LU) ; # 「LU」を出力

のように、処理の優先順位があるようです。
ソースを確認したところ、予めオプションをパースしておき、決まった順番で変換を適用していくようになっていました。
この部分はBoost.Spiritを使わず自前でパースするか、オプションを溜め込んで最後にeps_pで処理するかしないとダメですね。