ldo(2) 返り値

さて、 luaD_call に戻る。 firstResult が NULL でないとき、つまり C 関数のときは、各個の C 関数が適切な処理をしてくれるわけでこちらは関知しなくてよい。そうでないときは luaV_execute を実行するが、これも考えなくてよい。おおむね、 CallInfo にあるプログラムカウンタのところから実行していくだけだろうと推測されるし。

すべてが終ったら、 luaD_poscall で返り値をチェックしないといけない。

lua では多値を返すことができる。そこで、実際に「いくつの変数で結果を受けるか」という想定がないと返り値を適切に処理することができない。これが luaD_call の nResults であり、 luaD_poscall の wanted である。

void luaD_poscall (lua_State *L, int wanted, StkId firstResult) { 
  StkId res;
  if (L->hookmask & LUA_MASKRET)
    firstResult = callrethooks(L, firstResult);
  res = L->base - 1;  /* res == final position of 1st result */
  L->ci--;
  L->base = L->ci->base;  /* restore base */
  /* move results to correct place */
  while (wanted != 0 && firstResult < L->top) {
    setobjs2s(res++, firstResult++);
    wanted--;
  }
  while (wanted-- > 0)
    setnilvalue(res++);
  L->top = res;
}

返り値は firstResult から順に積まれているが、これを res にコピーする。 res はもともとの関数の呼出しの base である(baseは積まれるたびにインクリメントされるから、実際の始点は1だけ小さい)。あとは while ループでコピーしていくだけだ。ただ、 lua では、想定していた返り値の数よりも実際の返り値の方が少ないこともある。たとえば、

  function f() return 1; end
  a, b = f()

みたいなケースだ。この場合には、次の while ループで nil がセットされる。

ldo にはまだあと resume や yield といったトピックもあるのだが、これはややこしそうなので後回しにしたい。次は lopcode から VM 命令を調べ、 lvm を見るかな。

しかし、スタック操作は図に書かないとわかりづらいな。