- Code: Select all
tempTimer (0.3, [[ echo ("It is time") ]])
If you have a lot of timers running (for example in a speed walk script) this would be quite inefficient.
It would be more efficient and powerful if you could pass a function directly which only has to be compiled once. This would also enable using Lua closures. The Lua code would then look like this:
- Code: Select all
tempTimer (0.3, function () echo ("It is time") end)
-- or we could use a named function:
tempTimer (0.3, f)
Syntax errors get handled a lot sooner so debugging is easier. Another advantage would be that the code block would keep the current environment, while loadstring always uses the global environment. This would break out of any sandboxes.
In order to pass the function block through the C code you can use the Lua registry (http://www.lua.org/manual/5.1/manual.html#3.5).
I am not yet familiar with the Mudlet code and I do not know when I will have the time to explore it, so I cannot give a complete patch here, but still I try to give some code that should be relatively easy to integrate. My code snippets would make the code backwards compatible, it could still handle strings. (Though I would advise to remove this backward compatibility at a later point to make sandboxes possible).
My code snippets assume that there is an object associated with the callback. Its pointer is used as key value for the registry. As an alternative you could create some unique string.
- Code: Select all
CObjectWithCallback *pObject;
When setting the callback:
- Code: Select all
// save the argument #1 in the registry using a pointer to the object
// associated with the callback as key
lua_pushlightuserdata (L, pObject);
lua_pushvalue (L, 1);
lua_settable (L, LUA_REGISTRYINDEX);
When calling the callback function:
- Code: Select all
lua_pushlightuserdata (L, pObject);
lua_gettable (L, LUA_REGISTRYINDEX);
if (lua_isfunction (L, -1)) {
// here we should push any arguments, if the callback function is to be supplied with arguments
lua_call (L, 0, 0);
} else if (lua_isstring (L, -1)) {
// for backward compatibility, handle string callbacks although I would recommend to declare this
// as deprecated
char *s; size_t len;
s = lua_tolstring (L, -1, &len);
if (luaL_loadstring (L, s) != 0) {
// handle the error
} else {
// push arguments, if there are any
lua_call (L, 0, 0);
}
} else {
// we should have checked the type of the argument when setting the callback, so
// the program should never reach this
luaL_error (L, "wrong type for callback function");
}
Last but not least, the clean up:
- Code: Select all
// remove the function from the registry so the GC can deal with it
lua_pushlightuserdata (L, pObject);
lua_pushnil (L);
lua_settable (L, LUA_REGISTRYINDEX);
A similar solution could be used for the label callbacks. (Only the backward compatibility part would need to be changed). An advantage would be that anonymous functions can be used as callback and closures would be possible.
