突然始まった謎のシリーズ。概要をつかむのが主なので不正確だったり読み飛ばしがあります。CとGoとmrubyに関して素人なので、ツッコミはありがたいです。
gomruby.h
まずは唯一のCヘッダファイルから眺める。 static inline
で沢山関数も定義されている...。
L24 ~
Go で定義された関数と mruby/C の世界をブリッジするところ。
extern mrb_value *go_mrb_func_call(mrb_state*, mrb_value*, mrb_value*);
extern
キーワードを用いると、普通にGoのコード内でCから呼べる関数の中身が書けるっぽい。便利。
static inline mrb_value _go_mrb_func_call(mrb_state *s, mrb_value self)
例外を格納する mrb_value exc
を宣言しつつ上記のgo_mrb_func_callをそのまま呼んでいる。
static inline mrb_func_t _go_mrb_func_t() {
return &_go_mrb_func_call;
}
コメントにある通り、cgoはmrb_value
の共用体であるmrb_func_t
をうまく扱えないのでこういうやり方をしているらしい。
go_mrb_func_call
は Go の世界で定義される。 https://github.com/mitchellh/go-mruby/blob/master/func.go#L33 の通り、mrubyで呼ばれる処理本体をGoで定義して、その定義されやつらを格納したテーブルからlookupして呼び出すみたいなことをしている。
あとで見ると思うけど _go_mrb_func_t()
はGo側でメソッドを定義したら、必ずここを通ることになる。
L54 ~
mruby 側で渡されたメソッド引数をGoの世界に転送するところ。
extern void go_get_arg_append(mrb_value*);
引数である mrb_value
を Go の世界にパイプするための入り口。
static inline int _go_mrb_get_args_all(mrb_state *s) {
mrb_value *argv;
mrb_value block;
int argc, i, count;
count = mrb_get_args(s, "*&", &argv, &argc, &block);
for (i = 0; i < argc; i++) {
go_get_arg_append(&argv[i]);
}
if (!mrb_nil_p(block)) {
go_get_arg_append(&block);
}
return count;
}
書いてある通り。 mrb_get_args
を用いてそのステートの引数とブロックを取得し、
go_get_arg_append
に送り込むなどしている。
この辺の処理、むやみにややこしくなっている気がせんでもないんだけど、引数の受け渡しの制御をGoでやった方が並行処理されたときに安全になるみたいな話があるのかな?
L81 ~
こっから先は単純にCでやった方が早いものをCで実装しているだけのようだ。
static inline const char *_go_mrb_calc_send(const char *s)
はポインタ演算をして、
static inline void
_go_mrb_parser_set_capture_errors(struct mrb_parser_state *p, mrb_bool v)
はGoでbit fieladを扱えないのでラップしている、と言う感じっぽい。
L97 ~
あとは、マクロは cgo 経由で呼び出せないので関数と置き換えているところかな?
static inline mrb_aspec _go_MRB_ARGS_ANY() {
return MRB_ARGS_ANY();
}
static inline mrb_aspec _go_MRB_ARGS_ARG(int r, int o) {
return MRB_ARGS_ARG(r, o);
}
// ...
そして、続くかは不明なのであった...