Calling lua functions from .lua's using handles?

后端 未结 3 1452
渐次进展
渐次进展 2020-12-29 17:14

I\'m working on a small project trying to integrate lua with c++. My problem however is as follows:

I have multiple lua scripts, lets call them s1.lua s2.lua and s3.

相关标签:
3条回答
  • 2020-12-29 17:56

    The setfenv() function can be used to create a sandbox or environment for each file loaded.

    This example shows that all three files could be loaded with conflicting functions and that the functions can be called in any order. Similar code could be written in C++. This example only exports the print function to each environment, more might be needed in your scenario.

    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
    

    0 讨论(0)
  • 2020-12-29 17:56

    You could create a new state lua_newstate() for each file. This would be easier than my previous answer. However, it may have a performance penalty.

    0 讨论(0)
  • 2020-12-29 18:10

    This is effectively what gwell proposed using the 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;
    }
    

    Test scripts:

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

    Output:

    test1
    test2
    test2
    test1
    

    I omitted all error handling for brevity, but you'll want to check the return value of luaL_loadfile and use lua_pcall instead of lua_call.

    0 讨论(0)
提交回复
热议问题