祝! 軽量Rubyが公開
チョット目を離している隙に、軽量Ruby(mruby)が公開された様ですね。
Rails Hub情報局: ついに軽量Rubyの「mruby」のソースコードが公開!
軽量Rubyことmrubyのソースコードが公開されました - miyohide's blog
早速、GitHubからスナップショットを拾って来てビルドしてみました。
ビルド環境はCygwinです。make一発でインタプリタ(mruby)、コンパイラ(mrbc)、組込みサンプル(mrubysample)ができるようです。
$ ls -l bin 合計 5952 -rwxr-xr-x 1 shoz なし 1994838 4月 23 07:22 mrbc.exe -rwxr-xr-x 1 shoz なし 2025635 4月 23 07:22 mruby.exe -rwxr-xr-x 1 shoz なし 2022095 4月 23 07:22 mrubysample.exe
コンパイラmrbcでは次のオプションが使えます。
ruby 1.8.7 (2010-08-16 patchlevel 302) [i386-mingw32] Usage: ./mrbc [switches] programfile switches: -c check syntax only -oplace the output into -v print version number, then trun on verbose mode -B binary output in C language format -C function output in C language format --verbose run at verbose mode --version print the version --copyright print the copyright
オプション-Cは、RubyのコードをC言語の関数にトランスレートするようです。できたC言語のソースコードをmrubyのライブラリと合わせてコンパイル/リンクすることで、ターゲットのアプリに組み込めるようにしているのでしょう。
puts "hello world!"
このRubyのコードから下のようなC言語のソースコードができます。mrb_open()で得たmrb_state構造体をhello()の引数に渡せば動くようです。
#include "mruby.h" #include "irep.h" #include "mruby/string.h" #include "mruby/proc.h" static mrb_code iseq_0[] = { 0x01000006, 0x0180003d, 0x02000005, 0x010000a0, 0x0000004a, }; void hello(mrb_state *mrb) { int n = mrb->irep_len; int idx = n; mrb_irep *irep; mrb_add_irep(mrb, idx+1); irep = mrb->irep[idx] = mrb_malloc(mrb, sizeof(mrb_irep)); irep->idx = idx++; irep->flags = 0 | MRB_ISEQ_NOFREE; irep->nlocals = 2; irep->nregs = 4; irep->ilen = 5; irep->iseq = iseq_0; irep->slen = 1; irep->syms = mrb_malloc(mrb, sizeof(mrb_sym)*1); irep->syms[0] = mrb_intern(mrb, "puts"); irep->plen = 1; irep->pool = mrb_malloc(mrb, sizeof(mrb_value)*1); irep->pool[0] = mrb_str_new(mrb, "hello world!", 12); mrb->irep_len = idx; extern mrb_value mrb_top_self(mrb_state *mrb); mrb_run(mrb, mrb_proc_new(mrb, mrb->irep[n]), mrb_top_self(mrb)); }
int main() { mrb_state *mrb = mrb_open(); hello(mrb); return 0; }
オプション-Bを指定すると下の様なソースコードが得られます。Riteのバイトコードでしょうか? はっきりしたことは分かりません。
const char hello[] = { 0x52,0x49,0x54,0x45,0x30,0x30,0x30,0x39,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x39, 0x30,0x30,0x30,0x30,0x4d,0x41,0x54,0x5a,0x20,0x20,0x20,0x20,0x30,0x30,0x30,0x39, 0x30,0x30,0x30,0x30,0x00,0x00,0x00,0x83,0x00,0x01,0x00,0x00,0x20,0x20,0x20,0x20, 0x20,0x20,0x20,0x20,0xb3,0xd8,0x00,0x00,0x00,0x45,0x53,0x43,0x00,0x02,0x00,0x04, 0x00,0x02,0x6f,0x28,0x00,0x00,0x00,0x05,0x01,0x00,0x00,0x06,0x01,0x80,0x00,0x3d, 0x02,0x00,0x00,0x05,0x01,0x00,0x00,0xa0,0x00,0x00,0x00,0x4a,0xf5,0x07,0x00,0x00, 0x00,0x01,0x0f,0x00,0x0c,0x68,0x65,0x6c,0x6c,0x6f,0x20,0x77,0x6f,0x72,0x6c,0x64, 0x21,0x2b,0xac,0x00,0x00,0x00,0x01,0x00,0x04,0x70,0x75,0x74,0x73,0x24,0x89,0x00, 0x00,0x00,0x00, };
さて、仮想マシンのソースコードはsrc/vm.cにあります。中身をちょこっと見たところ、バイトコードの分岐はswich/case文による実装とDirect Threaded codeによる実装の2種類が用意されています‥‥"goto *optable[ほにゃら];"の書き方は gccの拡張機能でしたっけ? デフォールトではDirect Threaded code版になっているようです。