2010-12-24

從檔案載入 Lua function 至名稱空間

參考連結,可將 lua 檔案裡的程式載入到 namespace 裡,好處是可避免各個不同檔案裡出現相同 function 的問題。

稍微針對 C# 做了修改如下:

protected bool load_file_into_namespace(IntPtr L, string S, string N, bool bCall)
{
    lua_pushlstring(L, N, N.Length);
    lua_gettable(L, (-10002));
 
    if (lua_isnil(L, -1))
    {
        lua_pop(L, 1);
        lua_newtable(L);
        lua_pushlstring(L, N, N.Length);
        lua_pushvalue(L, -2);
        lua_settable(L, (-10002));
    }
    else
    {
        if (!lua_istable(L, -1))
        {
            lua_pop(L, 1);
            return (false);
        }
    }
 
    lua_newtable(L);
    lua_pushlstring(L, "_G", 2);
    lua_gettable(L, (-10002));
    lua_pushnil(L);
    while (lua_next(L, -2) != 0)
    {
        lua_pushvalue(L, -2);
        lua_pushvalue(L, -2);
        lua_settable(L, -6);
        lua_pop(L, 1);
    }
 
    if ((luaL_loadfile(L, S) > 0))
    {
        Console.Write("Error in file " + S + "!\n");
        for (int i = 0; ; i++)
            if ((lua_isstring(L, i) > 0))
            {
                Console.Write(lua_tolstring(L, i, IntPtr.Zero) + "\n");
            }
            else
                break;
        lua_error(L);
        lua_pop(L, 3);
        return (false);
    }
 
    if (bCall)
        lua_call(L, 0, 0);
    else
        lua_insert(L, -4);
 
    lua_pushnil(L);
    while (lua_next(L, -2) != 0)
    {
        lua_pushvalue(L, -2);
        lua_gettable(L, -5);
        if (lua_isnil(L, -1))
        {
            lua_pop(L, 1);
            lua_pushvalue(L, -2);
            lua_pushvalue(L, -2);
            lua_pushvalue(L, -2);
            lua_pushnil(L);
            lua_settable(L, -7);
            lua_settable(L, -7);
        }
        else
        {
            lua_pop(L, 1);
            lua_pushvalue(L, -2);
            lua_gettable(L, -4);
            if (!(lua_equal(L, -1, -2) > 0))
            {
                lua_pushvalue(L, -3);
                lua_pushvalue(L, -2);
                lua_pushvalue(L, -2);
                lua_pushvalue(L, -5);
                lua_settable(L, -8);
                lua_settable(L, -8);
            }
            lua_pop(L, 1);
        }
        lua_pushvalue(L, -2);
        lua_pushnil(L);
        lua_settable(L, -6);
        lua_pop(L, 1);
    }
 
    lua_pop(L, 3);
    return (true);
}

其中 S 表示檔案路徑, N 表示名稱空間。呼叫名稱空間內的 function 方式也會有些不同:

1) 以 luaL_dostring 方式呼叫:

假設載入的file0.lua 檔如下:
function pp()
  print("this is file0");
end

載入的 file1.lua 檔案下:
function pp()
  print("this is file1");
end

載入 file0.lua 時設定的 namespace 為 A0,載入 file1.lua 時設定的 namespace 為 A1,載入的程式碼為:
load_file_into_namespace(m_luaState, "file0.lua", "A0", true);
load_file_into_namespace(m_luaState, "file1.lua", "A1", true);

則分別呼叫 file0.lua及file1.lua內的 pp() 函數方式如下:
A0.pp();
A1.pp();

程式碼寫法是:
luaL_dostring(m_luaState, "A0.pp()");
luaL_dostring(m_luaState, "A1.pp()");

2) 以 lua_pcall 方式呼叫(以呼叫 A0.pp() 為例子)
lua_getglobal(m_luaState, "A0");
if (lua_type(m_luaState, -1) == 5)
{
    lua_getfield(m_luaState, -1, "pp");
 
    if (lua_type(m_luaState, -1) == 6)
    {
        // This removes the foo table from the stack
        lua_replace(m_luaState, -2); 
        ret = lua_pcall(m_luaState, 0, 0, 0);
 
        if (ret != 0)
        {
            lua_pop(m_luaState, 1);
        }
    }
    else
    {
        lua_pop(m_luaState, 2);
    }
 
}
else
{
    lua_pop(m_luaState, 1);
}

0 意見 :

張貼留言