lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


于 2011-8-31 8:26, Littlefield, Tyler 写道:
Hello:
Here's my revised execution function. Everything seems to work until I get to the pcall, where it fails. What am I doing wrong here?
Also, if there is a way to make this cleaner/remove the meta table after I'm done executing, I'd appreciate any advice.
[...]
hello

first I'd be sure that I got your intention correcty, so do you mean to do this with your `Execute' routine:

load each script code and execute it in a `sandbox' environment so that it won't pollute the global namespace

if so, I think you probably got some concept wrong.
the environment is just a `ordinary' table as the role of the global namespace.
you don't need to use a METATABLE as the environment (although it is totally legal.).
instead, you should set a metatable for the environment table, so that the original global names can be accessed.
in fact, this is just a `proxy table' patten, here we implement a `shadowed environment'.

for this `Execute' routine, you may implement it this way:
1. create a metatable for the shadowed environment, set the `__index' field as the original global namespace.
this should be done only once, and the metatable will be reused every new code is loaded.
2. you may save this metatable into the registry,
3. load the script code
4. create a 'clean' table to be used as the environment of the loaded chunk. set the metatable for it.
you may only store it on the stack, so it will be GC-ed at proper time. you don't need to remove it manually.
5. setfenv and pcall

the demo code may be like this (not tested):

------------------------------------------------------------------------

// ...
// some where in your initilization code
// create the metatable
lua_newtable(L); // create metatable, at -1
lua_pushvalue(L, LUA_GLOBALSINDEX); // get global table, at -1
lua_setfield(L, -2, "__index"); // set the __index field of metatable and pop, metatable at -1
lua_setfield(L, LUA_REGISTRYINDEX, "my_metatable"); // store the metatable into registry and pop, stack is now sane.
// ...

------------------------------------------------------------------------

// the Execute routine
void Script::Execute(Entity* obj, const std::string &code) {
if (!luaL_loadbuffer(state, code.c_str(), code.length(), "execution")) { // chunk is at -1
lua_newtable(state); // create shadow environment table at -1
lua_getfield(state, LUA_REGISTRYINDEX, "my_metatable"); // get metatable we created early from registry. at -1
lua_setmetatable(state, -2); // set metatable and pop, shadow env at -1
lua_setfenv(state, -2); // set env for chunk and pop, chunk at -1

int ret;
if (ret = lua_pcall(state, 0, 0, 0)) { // call the chunk at -1
// pcall error, handle error here
}
}
}

------------------------------------------------------------------------

hopefully may help.