mrib.c のソースコードを読む

PictRubyのirbはローカル変数を保持することができない、しかしmruby同梱のmirbはできる。その理由を調べるためにソースコードを読むことにした。

mrubyの中に同梱されているのでgit cloneしてソースコードを効率的に読むための準備をする。(要はMilkodeへの登録とタグファイルの作成)

ファイル構造を読んでいくと、結局のところmrib.cの中に全て同梱されていることがわかった。さらに読んでいくと怪しいのは以下の558行目辺り。

mruby/mirb.c:549

// irb内の無限ループの一部です

        /* pass a proc for evaulation */
        /* evaluate the bytecode */
        result = mrb_vm_run(mrb,
            proc,
            mrb_top_self(mrb),
            stack_keep);                       // ここで前回実行時のstack_keepを渡している
        stack_keep = proc->body.irep->nlocals; // 今回の実行結果をstack_keepに保存
        /* did an exception occur? */

mruby-evalのソースを読むと以下のようになっている

mruby/eval.c:216

static mrb_value
f_eval(mrb_state *mrb, mrb_value self)
{
  char *s;
  mrb_int len;
  mrb_value binding = mrb_nil_value();
  char *file = NULL;
  mrb_int line = 1;
  mrb_value ret;
  struct RProc *proc;

  mrb_get_args(mrb, "s|ozi", &s, &len, &binding, &file, &line);

  proc = create_proc_from_string(mrb, s, len, binding, file, line);
  ret = mrb_top_run(mrb, proc, mrb->c->stack[0], 0); // mrb_vm_runの代わりにmrb_top_runを読んでいる、後はなんとなく似ている?
  if (mrb->exc) {
    mrb_exc_raise(mrb, mrb_obj_value(mrb->exc));
  }

  return ret;
}

mrb_top_run()は中でmrb_vm_run()を読んでいるのでまぁ便利関数だろう。またnlocalsは

/* Program data array struct */
typedef struct mrb_irep {
  uint16_t nlocals;        /* Number of local variables */
  uint16_t nregs;          /* Number of register variables */

当たりを引いたのではないだろうか。前回evalしたときのnlocalsを保持して次回実行時に渡すような流れを作ればうまくいきそうな予感。まずは実験してみよう。