ためしてみよう、スタックトレース(stack backtrace)
JavaやLL言語ではよくある、「スタックトレース」を、OCamlでも出してみましょう。
ソース
mod1.ml(例外が発生):
let test () = (function (a::_) -> a) []
mod2.ml:
let test () = Mod1.test ()
main.ml:
let _ = Mod2.test ()
debug.ml
(* スタックトレースを出力するかどうかの設定 *) let mode _ = true
コンパイル with ocamlbuild
_tagsで、camlp4を使うように設定する。
not "debug.ml":pp(camlp4o -filter Camlp4ExceptionTracer)
あとは、ocamlbuidでコンパイル。
$ ocamlbuild main.byte
スタックトレースを出そう
普通に実行すると、スタックトレースがでてきます。
$ ./main.byte camlp4-debug: exc: File "mod1.ml", line 1, characters 15-20: Pattern matching failed at File "mod1.ml", line 1, characters 37-39 camlp4-debug: exc: File "mod1.ml", line 1, characters 15-20: Pattern matching failed at File "mod2.ml", line 1, characters 24-26 Fatal error: exception Match_failure("mod1.ml", 1, 15)
やってること。
camlp4コマンドを直接使うと、何をやっているかが分ります。
$ camlp4o -filter Camlp4ExceptionTracer mod2.ml let test () = try Mod1.test () with | (Stream.Failure | Exit as exc) -> raise exc | exc -> (if Debug.mode "exc" then Format.eprintf "camlp4-debug: exc: %s at File \"mod2.ml\", line 1, characters 24-26@." (Printexc.to_string exc) else (); raise exc)
ようするに、全ての関数にtry..withを加えて、例外を出力するようにしているだけです。
あとCamlp4ExceptionTracerは、3.10からの新機能らしいです。参考:Camlp4: Major changes。他にも内包表記やliftが使えるようになるライブラリもあるらしい。