Dconf 2017で出てきたコマンドラインスイッチ-vcg-ast
について書き残しておく。
これはgccでいう-E
オプションのようなもので、これはいろいろな"semantic steps" 1
がすべて終了したあとのASTを読めるかたちに書きだすオプションである。
-vcg-ast
が使われた動画。
使用箇所付近(25:00)から再生が始まる。
使ってみる
app.d
void main()
{
import std.stdio : writeln;
static immutable table = () {
import std.range : iota, array;
import std.algorithm : map;
import std.math : sqrt;
return 10.iota.map!((real n) => n.sqrt()).array;
}();
alias T = table;
mixin("writeln(T);");
}
ここで$ dmd app.d -vcg-ast
すると、app.d.cg
というファイルが生成される。
中を見たら7912行もあった。
app.d.cg
import object;
void main()
{
import std.stdio : writeln;
static immutable immutable(real[]) table = [0.00000L, 1.00000L, 1.41421L, 1.73205L, 2.00000L, 2.23607L, 2.44949L, 2.64575L, 2.82843L, 3.00000L];
alias T = static immutable immutable(real[]) table = [0.00000L, 1.00000L, 1.41421L, 1.73205L, 2.00000L, 2.23607L, 2.44949L, 2.64575L, 2.82843L, 3.00000L];
;
writeln(table);
return 0;
}
CommonType!(int, int)
alias CommonType = int;
CommonType!int
alias CommonType = int;
isFloatingPoint!int
enum bool isFloatingPoint = false;
Unqual!int
alias Unqual = int;
// 以下略
関数リテラルはCTFEの結果である配列になり、文字列mixinは普通のコードになり、さらにaliasも展開されている。
やたら行数が大きいのは自動的にimportされたobject
のせいだろう。
コードがコンパイラによってどのように展開されるかを知ることができてためになるし、なんだか見てて楽しい。
dubで使う
とりあえずdub使ってる人は、dub.jsonの場合、
— lempiji@思秋期 (@lempiji) 2017年5月5日
"configuration": [
{ "name": "ast", "dflag": ["-vcg-ast"] }
]
と書き足すなどしてビルドすると一発の模様です。
dub.json
{
"name": "test",
"authors": [
"kotet"
],
"description": "A minimal D application.",
"copyright": "Copyright © 2017, kotet",
"license": "proprietary",
"dependencies": {
"progress": "*"
},
"targetType": "executable",
"configurations": [
{
"name": "default"
},
{
"name": "ast",
"dflags": [
"-vcg-ast"
]
}
]
}
source/app.d
void main()
{
import std.stdio : writeln;
import std.range : iota;
import progress.bar : Bar;
auto b = new Bar();
foreach (n; b.iter(10.iota))
{
}
mixin("writeln(b);");
}
$ dub build -c ast
すると.d.cgファイルが出力される。
source/app.d.cg
import object;
void main()
{
import std.stdio : writeln;
import std.range : iota;
import progress.bar : Bar;
Bar b = new Bar;
{
Generator!int __r3001 = b.iter(iota(10));
for (; !__r3001.empty(); __r3001.popFront())
{
int n = __r3001.front();
}
}
writeln(b);
return 0;
}
// 以下略
foreach
がfor
に展開されている。
たのしい。