My solution was to build a hash table of the global environment before I loaded the main script. When I need to get the user defined globals I only display globals not present in the hash table. In this way the script can run at full speed without keeping track of globals in in runtime.
Example of my solution (this is the short version of my implementation):
// The hash table storing global names
std::set<unsigned int> Blacklist;
// Create hash table "Blacklist"
void BlacklistSnapshot(lua_State *L) {
lua_pushglobaltable(L);
lua_pushnil(L);
while (lua_next(L,-2) != 0) { // pop NIL, push name,value
Blacklist.insert(HashName(lua_tostring(L,-2))); // insert to hash table
lua_pop(L,1); // remove value
}
lua_pop(L,1); // Remove global table
}
// Display user defined globals only
void PrintGlobals(lua_State *L) {
lua_pushglobaltable(L);
lua_pushnil(L);
while (lua_next(L,-2) != 0) { // pop NIL, push name,value
// Check if the global is present in our blacklist
if (Blacklist.find(HashName(lua_tostring(L,-2))) == Blacklist.end()) {
// Not present, print it...
PrintFormattedVariable(lua_type(L,-1),lua_tostring(L,-2));
}
lua_pop(L,1); // remove value
}
lua_pop(L,1); // remove global table
}
void RunScript(void) {
// Create new Lua state
L = luaL_newstate();
// Load all Lua libraries
luaL_openlibs(L);
// Create co-routine
CO = lua_newthread(L);
BlacklistSnapshot(CO);
// Load and compile script
AnsiString script(Frame->Script_Edit->Text);
if (luaL_loadbuffer(CO,script.c_str(),script.Length(),"Test") == LUA_OK) {
lua_resume(CO,NULL,0);
} else {
cs_error(CO, "Compiler error: "); // Print compiler error
}
}
The function HashName
takes a string and returns the hash key for it as an unsigned int
, use whatever Hash algorithm you like here...
When you need to display the globals, call PrintGlobals()
(I do it from a hook
routine)