デフォルト引数の __LINE__, __FILE__

前少し話してた話なのですが。

プログラミング言語 D - Cプリプロセッサ vs D のマクロの項目 の 8 に C の assert マクロ vs 組み込み assert みたいな項があるんですが、これって assert 以外の名前でユーザ側で作りたい場合に、呼び出し側で毎度 __LINE__ とかつけなくちゃいけなくてとても不愉快。

というわけで、関数のデフォルト引数に __FILE__ と __LINE__ が渡された場合にだけ、呼び出し側の行数とファイル名を渡すというパッチを書いてみました。 GDC-0.20 向け。 DMD の部分しかいじってないのでたぶん DMD でもオケだけど。

http://shinh.skr.jp/tmp/default_linefile_gdc020_dmd0177.patch

a.d

void f(char[] f = __FILE__, int l = __LINE__) {
    printf("hello %.*s %d %.*s %d\n", f, l, __FILE__, __LINE__);
}

m.d

import a;

void main() {
    printf("hello %.*s %d\n", __FILE__, __LINE__);
    f();
}

こんな感じのを実行すると、

i@u src/gcc-4.0.3/obj> ./a.out
hello m.d 4
hello m.d 5 a.d 2

となります。まぁ便利かなぁと思うのですが。たぶん言語仕様的に変わる点は、

void f(char[] f = __FILE__, int l = __LINE__*2) {}

みたいな何がしたいかさっぱりわからん指定ができなくなったくらいかと思います。

    printf("hello %.*s %d\n", __FILE__, __LINE__*2);

は依然 OK 。

流れとしては、 TOKfile, TOKline を追加して __FILE__ と __LINE__ は lexer の段階では変化させない(lexer.c)→デフォルト引数のコンテキストで出てきた場合のみ FileExp, LineExp としておいて、その他の場合は StringExp と IntegerExp に通常通りなる(parse.c)→暗黙の型変換の部分は適当に素通りさせる(mtype.c)→ CallExp::semantic でデフォルト引数適用する部分に割込む(expression.c)

あとデフォルトテンプレート引数はいじってない。

追記:

void f(char[] f = __FILE__, int l = 2*__LINE__) {}

が通るしキモい。んーめんどいな。普通に考えると両方エラーが良さそうに思うけど、それって簡単だっけなぁ。うーんどうすべきなんだろう。

あと忘れてたけど、

t->ustring = (unsigned char *)(loc.filename ? loc.filename : mod->ident->toChars());

これ安易にコメントアウトしてるけど、 mod->ident->toChars() が採用されるっていうか、 loc.filename が NULL のシーンっていつあるのかよくわかってないのであった。これも後で調べるとメモ。

なにかあれば下記メールアドレスへ。
shinichiro.hamaji _at_ gmail.com
shinichiro.h