SMLUnitをPoly/MLに対応した

SMLUnitというSML用ユニットテストライブラリをPoly/ML5.8から使えるようにしました。
makeと上手く連携するMakefileが書けたので満足です。
ブランチはここ> https://github.com/eldesh/SMLUnit/tree/support/polyml *1

使い方はReadmeに書いたけど、Poly/MLの機能の解説もしつつここにもまとめておこう。

使い方

まずREPLでの使い方。

Poly/MLは PolyML.make: string -> unit という関数にディレクトリ名を与えると、そのディレクトリ以下の ml_bind.ML みたいな名前のファイルを探してきて読み込みます。
さらに ml_bind.ML の中で structure, signature, functor に言及すると、それらと同名のファイルを探してきて読み込みます。
ちゃんとmakeなので(?)2回目以降は前回読んだ時から更新されたファイルだけ読み込んでくれるので便利です。

SMLUnit$ poly --eval 'PolyML.suffixes := ".sig"::(!PolyML.suffixes)'
> PolyML.make "src/main";
Making main
Making SMLUnit
..
structure SMLUnit: SMLUNIT
val it = (): unit

--eval には PolyML.make が探すファイル名の拡張子を追加するコードを渡しています。
こうしておくと未知のシグネチャ名に言及したときに .sig ファイルも探してくれます。

ビルド

SMLUnitはユニットテストライブラリなので当然他のライブラリからも参照したいですね。
でも実はPolyML.makeは、その時点でのカレントディレクトリからの相対パスでファイルを探すので*2、無関係なディレクトリから参照しづらいという問題があります。
そこでコンパイルした結果をモジュールエクスポートという機能を使って書き出しておきます。

SMLUnit$ make -f Makefile.polyml
echo "" | poly -q --error-exit --eval 'PolyML.suffixes := ".sig"::(!PolyML.suffixes)' \
        --eval 'PolyML.make "src/main"' \
        --use export.sml \
        --eval 'PolyML.SaveState.saveModule ("libsmlunit.poly", SMLUnit)'
Making main
Making SMLUnit
..
Created structure SMLUnit

デフォルトターゲットをmakeすると、PolyML.SaveState.saveModuleを使ってSMLUnitの公開するモジュールが ./libsmlunit.poly に書き出されます。
このファイルは普通にREPLからも読めますのでライブラリのデバッグなどに便利です*3

> PolyML.loadModule "./libsmlunit.poly";
signature ASSERT =
  sig
..
signature TESTRUNNER =
  sig type parameter val runTest: parameter -> Test.test -> unit end
val it = (): unit

(他ライブラリからの)使い方

Poly/MLでプログラムの最終結果(実行ファイル)を得るには、まずPolyML.export: string * (unit -> 'a) -> unitという関数に適切なオブジェクトファイル名とエントリーポイントになる関数(要はmain関数)を渡します。
その際あらかじめ依存しているライブラリ(libsmlunit.poly)をロードしておきます:

> PolyML.loadModule "/path/to/libsmlunit.poly"; (* 依存している SMLUnit を読み込む *)
> PolyML.make "hoge/src"; (* 利用側のコードを読み込む *)
> PolyML.export ("libhoge.o", Main.main); (* main: unit -> unit をエクスポート *)

そしてエクスポートしたオブジェクトファイルをpolycコマンドでリンクして完了です。

$ polyc -o hoge libhoge.o
./hoge
..

*1:まだ先にやりたいことがあってマージはしてない

*2:これは今読んでいるファイルからの相対パスに修正するべきだと思う

*3:この形式でビルドされるライブラリが存在すれば。。。