読者です 読者をやめる 読者になる 読者になる

Lua5.2でluaの函数内にてエラった時にtracebackを取得するには

Luaを自分のプログラムに組み込んでなんやらしている時に、

local function g()
  prin("hoge") -- 本当はprint("hoge")と書きたかった.
end

local function f()
  g()
end

f()

というコードがあるとして、これを実行するために、

  int error_code = lua_pcall(L,
                             nargs,
                             nresults,
                             0);
  if (error_code)
    {
      luaL_traceback(L,
                     L,
                     lua_tostring(L,
                                   1),
                     1);
      std::cout << lua_tostring(L, 1) << std::endl;
    }

なんて事をしても、lua_pcall()終了時点でstackは空になっているためtraceback自体表示されない. 正しくは、

namespace
{

int
traceback(lua_State* L)
{
  const char* message(lua_tostring(L,
                                   1));
  if (message)
    {
      luaL_traceback(L,
                     L,
                     message,
                     1);
    }
  else if (!lua_isnoneornil(L, 1))
    {
      if (!luaL_callmeta(L, 1, "__tostring"))
        {
          lua_pushliteral(L,
                          "(no error message)");
        }
    }

  return 1;
}

}
...

int error_func = lua_gettop(L) - nargs; // 呼び出した函数のstack数で引く
lua_pushcfunction(L,
                  traceback); // traceback函数をpush
lua_insert(L,
           error_func);
error_code = lua_pcall(L,
                       nargs,
                       nresults,
                       error_func); //traceback函数のhandle(index)を指定
lua_remove(L,
           error_func);

if (error_code)
  {
    const char* error_message(lua_tostring(L,
                                           1));
    std::cout << "luaL_pcall:";
    std::cout << error_message << std::endl;
    lua_close(L);
    return 1;
  }

...

これで、

luaL_pcall:[string "?"]:3: attempt to call global 'prin' (a nil value)
stack traceback:
    [string "?"]:3: in function 'g'
    [string "?"]:7: in function 'f'
    [string "?"]:10: in main chunk

というようにちゃんとstack tracebackが表示される.