`(Hello ,world)

ツッコミ、添削大歓迎です。いろいろ教えてください。

2009-07-14

各言語のエラー情報

Gaucheはエラーが出たときに、スタックトレースは出力されるが肝心なエラーの発生したソース位置がわからないのが辛い。

RubyLua がシンプルかつ十分な情報で好みかな。Squirrelはローカル変数まで表示されてイイ!

Lispの中ではYpsilonのエラーメッセージが一番わかりやすい。

Gauche
gosh> (fib "hello")
*** ERROR: real number required: "hello"
Stack Trace:
_______________________________________
Ypsilon
> (fib "hello")

error in |comparison(< > <= >=)|: expected number, but got "hello", as argument 1

irritants:
  ("hello" 2)

backtrace:
  0  (< n 2)
  ..."d:/home/repos/misc/lisp/errmsg/fib.scm" line 2
  1  (+ (fib (- n 1)) (fib (- n 2)))
  ..."d:/home/repos/misc/lisp/errmsg/fib.scm" line 4
  2  (fib "hello")
  ..."/dev/stdin" line 1
Mosh
mosh>(fib "hello")

Unhandled exception:

 Condition components:
 1. &assertion
 2. &who             who: "<"
 3. &message         message: "number required required, but got (hello 2)"
 4. &irritants       irritants: ()
SBCL
* (fib "hello")

debugger invoked on a SIMPLE-TYPE-ERROR: Argument X is not a REAL: "hello"

Type HELP for debugger help, or (SB-EXT:QUIT) to exit from SBCL.

restarts (invokable by number or by possibly-abbreviated name):
  0: [ABORT] Exit debugger, returning to top level.

(SB-KERNEL:TWO-ARG-< "hello" 2)
0] (backtrace)

0: (SB-KERNEL:TWO-ARG-< "hello" 2)
1: ("no debug information for frame")
2: (SB-INT:SIMPLE-EVAL-IN-LEXENV (FIB "hello") #<NULL-LEXENV>)
3: (INTERACTIVE-EVAL (FIB "hello"))[:EXTERNAL]
4: (SB-IMPL::REPL-FUN NIL)
5: ((LAMBDA ()))
6: (SB-IMPL::%WITH-REBOUND-IO-SYNTAX #<CLOSURE (LAMBDA #) {23B5A735}>)
7: (SB-IMPL::TOPLEVEL-REPL NIL)
8: (SB-IMPL::TOPLEVEL-INIT)
9: ((LABELS SB-IMPL::RESTART-LISP))
10: ("foreign function: #x4120C4")
11: ("foreign function: #x40AF88")
Ruby
irb(main):002:0> fib "hello"
ArgumentError: comparison of String with 2 failed
        from ./fib.rb:2:in `<'
        from ./fib.rb:2:in `fib'
        from (irb):2
        from :0
Python
>>> fib.fib("hello")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "fib.py", line 5, in fib
    return fib(n-1) + fib(n-2);
TypeError: unsupported operand type(s) for -: 'str' and 'int'

「"hello" < 2」はOK (False)で「"hello" - 1」がだめとか。わけわからん。

Lua
> fib("hello")
fib.lua:2: attempt to compare string with number
stack traceback:
        fib.lua:2: in function 'fib'
        stdin:1: in main chunk
        [C]: ?
Squirrel
sq>fib("hello")

AN ERROR HAS OCCURED [comparsion between 'hello' and '2']

CALLSTACK
*FUNCTION [fib()] fib.nut line [2]
*FUNCTION [main()] interactive console line [1]

LOCALS
[n] "hello"
[this] TABLE
[vargv] ARRAY
[this] TABLE
Crowbar
$ ./crowbar.exe fib.crb
  2:2項演算子>のオペランドの型が不正です。
Xtal
$ bin/xtal.exe fib.xtal
lib::builtin::UnsupportedError: lib::builtin::String::op_lt#<lib::builtin::Int>は定義されていません。
        fib.xtal:2: in filelocal::fib
        fib.xtal:9: in (instance of AnonymousClass) fib.xtal(1)

ちょw

Gaucheでのエラーの捕捉

CからGaucheの関数を呼び出すときに

	ScmEvalPacket epak;
	if (Scm_Apply(proc, args, &epak) >= 0) {
		...

としていたが、Scheme内でエラーが発生したときに例外オブジェクトは ScmEvalPacket::exception で取れるが、どこでエラーが起きたかとかの情報が出ないので困る。

404 Error - FC2ブログを見て、Gauchereplをまねてみたがうまくいかず…。

C側ではほとんど何もしてなくて、エラーをキャッチできてもどうやって復帰させるかの方法は知らないのでScheme側でキャッチしちゃっていいんじゃないの?と考えてguardなどを使えばいいんじゃないかと思ったけど、これも例外が取れるだけでどこで発生したかがわからない。

すったもんだしてたところ、Scm_Apply()の代わりにScm_ApplyRec()を使えばgoshで出るエラーメッセージが出力されスタックトレースも出力されることがわかった。ただこれだと、例外が投げられてめぐりめぐってvm.cのuser_eval_inner()内の

            ...
            else if (vm->cstack->prev == NULL) {
                /* This loop is the outermost C stack, and nobody will
                   capture the error.  Usually this means we're running
                   scripts.  We can safely exit here, for the dynamic
                   stack is already rewound. */
                exit(EX_SOFTWARE);
            } ...

exit()が呼び出されてアプリが強制終了してしまう。

あれこれ試してたところ、SCM_UNWIND_PROTECT を使えばいいことがわかった:

	SCM_UNWIND_PROTECT {
		ScmObj r = Scm_ApplyRec(Scm_SymbolValue(module, SCM_SYMBOL(SCM_INTERN("main"))), SCM_NIL);
	} SCM_WHEN_ERROR {
		printf("error\n");
	} SCM_END_PROTECT;

まだAPIが確定してないから勝手に使われると困るからドキュメント書かない、とかもわかるんだけどあれこれ手探りで探すの大変なので、将来変わってもいいから現在はこうなってるとかこう想定して作ってるとかいうメモ書きがあるといいなぁと思う。

トラックバック - http://cadr.g.hatena.ne.jp/mokehehe/20090714