[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: packaging for embedded interpreter
- From: Adrian Sietsma <adrian_groups@...>
- Date: Thu, 13 Jan 2005 19:05:35 +1000
edwin@itasca.net wrote:
OK, I read the stuff people suggested on "sandbox" and environments, and
I think I ALMOST understand it, but I've still got a couple of questions.
I've got a c program that embeds a lua interpreter that looks basically
like this in the critical part:
lua_dofile(L, "script1.lua");
lua_dofile(L, "script2.lua");
while (running)
{
//retrieve function, which has to be packaged for script1
lua_pushstring(L, "doSomething");
lua_gettable (L, LUA_GLOBALSINDEX);
//push argument
lua_pushnumber(L, 23);
//call function
lua_call(L,1,1);
//retrieve return value
lua_Number num = lua_tonumber(L, -1);
//AND NOW I DO IT AGAIN FOR "doSomething" packaged for script2
}
and the lua scripts (both of them) essentially look like this:
somevar = 1
function doSomething(num)
mynum=mutate (num)
return mynum
end
function mutate (innum)
--dosomething with innum and return a result
end
if there is only one return value (a function) in each script, you could
make each script return a function with local upvalues :
<at the top>
local somevar, doSomething, mutate
<at the bottom>
return doSomething
<in the c>
int s1, s2, tos,tos1; // these could be -ve stack offsets,
// but i prefer variables
tos = lual_gettop(L); // top of stack for restore
// in c++, const int tos = lua_gettop(L)
lua_dofile(L,"script1.lua"); // function script1.doSomething at tos
s1 = lual_gettop(L); // script1 function index
lua_dofile(L,"script2.lua"); // function script2.doSomething at tos
tos1 = s2 = lual_gettop(L); // script2 function index
while (running)
{
lua_pushvalue(s1); //retrieve function for script1
lua_pushnumber(L, 23); //push argument
lua_call(L,1,1); //call function
lua_Number num = lua_tonumber(L, -1);//retrieve return value
// use num ??
lua_settop(L,tos1); // tidy stack
//AND NOW DO IT AGAIN FOR script2 "doSomething"
lua_pushvalue(s2); //retrieve function for script2
lua_pushnumber(L, 23); //push argument
lua_call(L,1,1); //call function
lua_Number num = lua_tonumber(L, -1);//retrieve return value
// use num ??
lua_settop(L,tos1); // tidy stack
}
lua_settop(L,tos); // tidy stack
if you have lots of functions, return a table :
<at the top>
local somevar, doSomething, mutate
<at the bottom>
return {do = doSomething, mutate = mutate }
<in the c>
load scripts as above : return is now table
lookup script func as you were, but from local table rather than globals
(as below).
however, your question was :
What I need is some way to create namespaces for the stuff in each lua
script that is loaded in with lua_dofile so that C can lua_call
script1.doSomething and it will correctly call script1.mutate and use
the correct local variables and such.
If I understand the "Programming in Lua" book in section 15.4, the
solution is to create a custom environment for each of the chunks
read in by lua_dofile
yep. it can be done in c
int mt, s1, s2, tos,tos1; // these could be -ve stack offsets,
// but i prefer variables
tos = lua_gettop(L);
lua_newtable(L); // metatable
mt = lua_gettop(L);
lua_pushstring(L,"__index")
lua_lua_gettable (L, LUA_GLOBALSINDEX)
lua_settable(L,-1); // metetable __index = global environ.
lua_newtable(L); //env. for s1
s1 = lua_gettop(L);
lua_pushvalue(L,mt);
lua_setmetatable(L, -2); // set meta to globals
lua_newtable(L); //env. for s2
s2 = lua_gettop(L);
lua_pushvalue(L,mt);
lua_setmetatable(L, -2); // set meta to globals
if (luaL_loadfile(L, "script1.lua") != 0)
lua_error(L);
lua_pushvalue(L,s1);
lua_setfenv(L,-2); // set env of script1 chunk
lua_call(L, 0, LUA_MULTRET, 0) != 0) // execute script
if (luaL_loadfile(L, "script2.lua") != 0)
lua_error(L);
lua_pushvalue(L,s2);
lua_setfenv(L,-2); // set env of script1 chunk
lua_call(L, 0, LUA_MULTRET, 0); // execute script
tos1 = lua_gettop(L);
while (running)
{
lua_pushstring(L, "doSomething");
lua_gettable (L, s1); //lookup func in s1 environment.
lua_pushnumber(L, 23); //push argument
lua_call(L,1,1); //call function
lua_Number num = lua_tonumber(L, -1);//retrieve return value
// use num ??
lua_settop(L,tos1); // tidy stack
//AND NOW DO IT AGAIN FOR script2 "doSomething"
lua_pushstring(L, "doSomething");
lua_gettable (L, s2); // lookup func in s2
lua_pushnumber(L, 23); //push argument
lua_call(L,1,1); //call function
lua_Number num = lua_tonumber(L, -1);//retrieve return value
// use num ??
lua_settop(L,tos1); // tidy stack
}
lua_settop(L,tos); // tidy stack
or in lua
, using this little bit:
local P={} --create an empty list as the environment
package = P --??
local _G = _G --make a local copy of the global environment in case I need
--anything from it
setfenv(1,P) --set environment of this "function"
1) how is "local P={}; package=P" different from "local package = {}"?
the first gives local P, global package. the second gives local package.
2) WHERE do I put the packaging bit in the script files? At the top,
ahead of the functions that get lua_called, or in the one that gets
lua_called? If it goes in the function, any variables global to
the script (like somevar) will in fact be global to L, right?
3) do I understand correctly that when I create an initial empty
environment I basically can't get to anything from the standard
libraries and such, and therefore pretty much HAVE TO make
local copies of everything I need before I setfenv?
you can set a metatable in the local environment pointing to the global
one, if your scripts need to see everything.
setmetatable(t,{__index=_G})
Adrian
ps this is _not_ tested code, just a mish-mash of cut-and-paste bits.