Rua: 例外ハンドラを受け取るようにした

http://storehouse.sakura.ne.jp/viewvc/viewvc.cgi/rua/rua/rua.c?root=svn&view=markup

ソース

static int rua_proc_call(lua_State *L) {
  VALUE proc, args, retval, error_handler, errargs, errmsg;
  int i, n, status;

  proc = (VALUE) lua_touserdata(L, lua_upvalueindex(1));
  error_handler = (VALUE) lua_touserdata(L, lua_upvalueindex(2));
  args = rb_ary_new();
  n = lua_gettop(L);

  for (i = 0; i < n; i++) {
    rb_ary_push(args, rua_torbval(L, i + 1, error_handler));
  }

  rb_ary_push(args, proc);
  retval = rb_protect(_rua_proc_call, args, &status);

  if (status != 0) {
    if (rb_obj_is_kind_of(error_handler, rb_cProc)) {
      errargs = rb_ary_new();
      rb_ary_push(errargs, ruby_errinfo);
      rb_ary_push(errargs, error_handler);
      retval = rb_protect(_rua_proc_call, errargs, &status);

      if (status != 0) {
        errmsg = rb_check_convert_type(ruby_errinfo, T_STRING, "String", "to_s");
        fprintf(stderr, "warning: %s\n", StringValuePtr(errmsg));
      }
    } else {
      retval = Qnil;
    }
  }
  
  rua_pushrbval(L, retval, error_handler);
  return 1;
}

Rubyで実行

require 'rua'

rua = Rua.new(lambda {|e|
  puts <<-EOS
  | error handler called.
  | -----
  | #{e.backtrace.join("\n  | ")}
  | -----
  EOS
})

rua.openlibs(:all)

rua[:rb_func] = lambda do |x|
  puts "rb_func(#{x}) called."
  raise 'xxxxx'
end

lua_func = rua.eval(<<EOS)
  rb_func('in lua')
  lua_func =  function(x)
    print('lua_func(' .. x .. ') called.')
  end
  lua_func('in lua')

  return lua_func
EOS

rb_func = rua[:rb_func]

lua_func.call("in ruby")
rb_func.call("in ruby")


rb_func(in lua) called.
| error handler called.
| -----
| foo.rb:16
| foo.rb:19:in `call'
| foo.rb:19:in `eval'
| foo.rb:19
| -----
lua_func(in lua) called.
lua_func(in ruby) called.
rb_func(in ruby) called.
| error handler called.
| -----
| foo.rb:16
| foo.rb:32:in `call'
| foo.rb:32
| -----
ハンドラを引数で持ちまわっているのが、ちょっとかっこ悪い…struct ruaを直接渡すようにすればよかったかも。
ruby_errinfoはスレッドセーフって考えていいのかな?