Песочница Embedded Lua в 5.2 / Установить среду для функций из lua.file

Допустим, у меня есть как минимум два файла сценария lua.

test1.lua test2.lua

оба определяют функцию init и другие функции с похожими именами.

Как я могу загрузить каждый файл скрипта, используя C++/c, в отдельную среду, использующую Lua 5.2, чтобы те же имена функций не конфликтовали - я нашел пример кода для 5.1, который мне не подходит (потому что setenv пропал, а lua_setuservalue - нет). похоже на работу)

Пример здесь Вызов функции lua из.lua с помощью ручек?

В основном, если я заменяю setenv на setuservalue - я получаю нарушение прав доступа.

2 ответа

Решение

В неофициальном FAQ по Lua есть запись о песочнице в Lua. Я предполагаю, что вы можете достаточно легко перенести эту логику в ваш код C/C++.

Смотрите также LuaFiveTo на вики-сайте lua-users.

коррекция

Это действительно не так тривиально, как казалось. Но в конце концов все просто: загрузите свой чанк, нажмите на таблицу _ENV, используйте lua_setupvalue(L,-2,1), Важно то, что таблица должна быть на вершине стека.

В качестве небольшого примера, используя 2 среды по умолчанию _G для чтения содержимого через метатаблицы:

#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>

int main(void){
        lua_State *L = luaL_newstate();
        char *file1 = "file1.lua";
        char *file2 = "file2.lua";

        luaL_openlibs(L);

        luaL_loadfile(L,file2); // S: 1
        luaL_loadfile(L,file1); // S: 2
        lua_newtable(L); // ENV for file 1: S: 321
        lua_newtable(L); // ENV for file 2: S: 4321

        //lets have each function have its metatable, where missed lookups are
        //instead looked up in the global table _G

        lua_newtable(L); // metatable S: 54321
        lua_getglobal(L,"_G"); // pushes _G, which will be the __index metatable entry S: 654321

        lua_setfield(L,-2,"__index"); // metatable on top S: 54321
        lua_pushvalue(L,-1); // copy the metatable S: 554321
        lua_setmetatable(L,-3); // set the last copy for env2 S: 54321
        lua_setmetatable(L,-3); // set the original for env1  S: 4321
        // here we end up having 2 tables on the stack for 2 environments
        lua_setupvalue(L,1,1); // first upvalue == _ENV so set it. S: 321
        lua_setupvalue(L,2,1); // set _ENV for file S: 21
        // Remaining on the stack: 2 chunks with env set.
        lua_pcall(L,0,LUA_MULTRET,0);
        lua_pcall(L,0,LUA_MULTRET,0);
        lua_close(L);
        return 0;
}

И для 2 файлов Lua:

-- file1.lua
function init()
        A="foo"
        print("Hello from file1")
        print(A)
end
init()

-- file2.lua
-- this shows that stuff defined in file1 will not polute the environment for file2
print("init function is",tostring(init))
function init()
        A="bar"
        print("Hello from file2")
        print(A)
end
init()

оба определяют функцию init и другие функции с похожими именами.

Прежде всего, почему эти функции глобальны? Они должны быть локальными для сценария. Если вы собираетесь require их в других файлах, они должны создать и вернуть таблицу, содержащую функции, которые они хотят представить.

Современная идиома, когда требуются эти файлы - это сделать что-то вроде этого:

local Library = require 'library'

Library.Func1(...)

Таким образом, вы не загрязняете глобальное пространство имен Lua. Вы используете локальные переменные.

Однако, если вы настаиваете на использовании глобальных переменных, подобных этому, вы можете сделать именно то, что сказано в документации: изменить первое значение скомпилированного фрагмента.

В основном, если я заменяю setenv на setuservalue - я получаю нарушение прав доступа.

Конечно, у вас. Это не то lua_setuservalue делает Это для установки значений, связанных с пользовательскими данными. То, что вы хотите, соответственно называется lua_setupvalue,

Используя приведенный вами пример кода, правильный ответ будет следующим:

lua_setupvalue(L, -2, 1);
Другие вопросы по тегам