Вызов функции lua из .lua использует дескрипторы? - PullRequest
0 голосов
/ 08 августа 2010

Я работаю над небольшим проектом, пытающимся интегрировать lua с c ++. Моя проблема, однако, заключается в следующем:

У меня есть несколько сценариев lua, давайте назовем их s1.lua s2.lua и s3.lua. Каждый из них имеет следующие функции: setVars () и executeResults ().

Теперь я могу вызывать файл lua через LuaL_dofile и сразу после использования setVars () и / или executeResults (). Однако проблема в том, что после загрузки s2.lua я больше не могу вызывать функции s1.lua. Это означало бы, что мне нужно повторить LuaL_dofile на s1.lua, чтобы восстановить доступ к функции, и в результате я потеряю доступ к функциям в s2.lua.

Есть ли способ просто загрузить все файлы lua подряд, а потом начать вызывать их функции по желанию? Что-то вроде s1-> executeResults () s5-> executeResults () s3-> setVars () и т. Д.

У меня уже есть система, использующая boost :: filesystem для обнаружения всех файлов lua в папке, затем я сохраняю имена этих файлов в векторе, а затем просто перебираю вектор, чтобы загрузить каждый файл lua в строке.

Прежде чем заполнить вектор именами файлов lua, моя функция загрузки плагина на данный момент выглядит так:

void Lua_plugin::load_Plugins(){
 std::vector<std::string>::const_iterator it;
 for (it=Lua_PluginList.begin(); it!=Lua_PluginList.end(); it++){
  std::cout<<"File loading: " << *it << std::endl;
  std::string filename =  *it;
  std::string filepath = scriptdir+filename;
  if (luaL_loadfile(L, filepath.c_str()) || lua_pcall(L, 0, 0, 0)) {
   std::cout << "ScriptEngine: error loading script. Error returned was: " << lua_tostring(L, -1) << std::endl;
  }
 }
}

Чтобы было немного яснее, все, что у меня есть в .lua, примерно так:

-- s1.lua

setVars()
--do stuff
end

executeResults()
--dostuff
end

и т. Д., Но я хотел бы иметь возможность вызывать s1.lua setVars () и s2.lua setVars () после простой загрузки обоих в ряд.

Ответы [ 3 ]

5 голосов
/ 09 августа 2010

Это фактически то, что gwell предложил с использованием C API:

#include <stdio.h>

#include "lua.h"

static void
executescript(lua_State *L, const char *filename, const char *function)
{
    /* retrieve the environment from the resgistry */
    lua_getfield(L, LUA_REGISTRYINDEX, filename);

    /* get the desired function from the environment */
    lua_getfield(L, -1, function);

    return lua_call(L, 0, 0);
}

static void
loadscript(lua_State *L, const char *filename)
{
    /* load the lua script into memory */
    luaL_loadfile(L, filename);

    /* create a new function environment and store it in the registry */
    lua_createtable(L, 0, 1);
    lua_getglobal(L, "print");
    lua_setfield(L, -2, "print");
    lua_pushvalue(L, -1);
    lua_setfield(L, LUA_REGISTRYINDEX, filename);

    /* set the environment for the loaded script and execute it */
    lua_setfenv(L, -2);
    lua_call(L, 0, 0);

    /* run the script initialization function */
    executescript(L, filename, "init");
}

int
main(int argc, char *argv[])
{
    lua_State *L;
    int env1, env2;

    L = (lua_State *) luaL_newstate();
    luaL_openlibs(L);

    loadscript(L, "test1.lua");
    loadscript(L, "test2.lua");

    executescript(L, "test1.lua", "run");
    executescript(L, "test2.lua", "run");
    executescript(L, "test2.lua", "run");
    executescript(L, "test1.lua", "run");

    return 0;
}

Тестовые сценарии:

-- test1.lua
function init() output = 'test1' end
function run() print(output) end

-- test2.lua
function init() output = 'test2' end
function run() print(output) end

Вывод:

test1
test2
test2
test1

Для краткости я опустил всю обработку ошибок, но вы захотите проверить возвращаемое значение luaL_loadfile и использовать lua_pcall вместо lua_call.

1 голос
/ 09 августа 2010

Вы можете создать новое состояние lua_newstate() для каждого файла.Это было бы проще, чем мой предыдущий ответ.Тем не менее, это может привести к снижению производительности.

1 голос
/ 08 августа 2010

Функцию setfenv() можно использовать для создания песочницы или среды для каждого загруженного файла.

В этом примере показано, что все три файла могут быть загружены конфликтующими функциями и что эти функции можно вызывать в любом порядке. Подобный код может быть написан на C ++. В этом примере экспортируется только функция печати в каждую среду, в вашем сценарии может потребоваться больше.

function newEnv()
  -- creates a simple environment
  return {["print"]=print}
end

local e={} -- environment table
local c    -- chunk variable

-- first instance
c = loadstring([[function f() print("1") end]])
e[#e+1] = newEnv()
setfenv(c, e[#e]) -- set the loaded chunk's environment
pcall(c) -- process the chunk (places the function into the enviroment)

-- second instance
c = loadstring([[function f() print("2") end]])
e[#e+1] = newEnv()
setfenv(c, e[#e])
pcall(c)

-- third instance
c = loadstring([[function f() print("3") end]])
e[#e+1] = newEnv()
setfenv(c, e[#e])
pcall(c)

pcall(e[3].f) --> 3
pcall(e[2].f) --> 2
pcall(e[1].f) --> 1
pcall(e[1].f) --> 1
pcall(e[2].f) --> 2
pcall(e[3].f) --> 3

...