Skip to content

Commit

Permalink
Move script_run_callbacks to Lua
Browse files Browse the repository at this point in the history
  • Loading branch information
ShadowNinja committed Dec 8, 2013
1 parent 96f753a commit a0dce51
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 84 deletions.
39 changes: 39 additions & 0 deletions builtin/misc_register.lua
Expand Up @@ -314,6 +314,45 @@ minetest.register_item(":", {
groups = {not_in_creative_inventory=1},
})


function minetest.run_callbacks(callbacks, mode, ...)
assert(type(callbacks) == "table")
local cb_len = #callbacks
if cb_len == 0 then
if mode == 2 or mode == 3 then
return true
elseif mode == 4 or mode == 5 then
return false
end
end
local ret = nil
for i = 1, cb_len do
local cb_ret = callbacks[i](...)

if mode == 0 and i == 1 then
ret = cb_ret
elseif mode == 1 and i == cb_len then
ret = cb_ret
elseif mode == 2 then
if not cb_ret or i == 1 then
ret = cb_ret
end
elseif mode == 3 then
if cb_ret then
return cb_ret
end
ret = cb_ret
elseif mode == 4 then
if (cb_ret and not ret) or i == 1 then
ret = cb_ret
end
elseif mode == 5 and cb_ret then
return cb_ret
end
end
return ret
end

--
-- Callback registration
--
Expand Down
102 changes: 18 additions & 84 deletions src/script/common/c_internal.cpp
Expand Up @@ -66,101 +66,35 @@ void script_error(lua_State *L)
// Then push nargs arguments.
// Then call this function, which
// - runs the callbacks
// - removes the table and arguments from the lua stack
// - pushes the return value, computed depending on mode
// - replaces the table and arguments with the return value,
// computed depending on mode
void script_run_callbacks(lua_State *L, int nargs, RunCallbacksMode mode)
{
// Insert the return value into the lua stack, below the table
assert(lua_gettop(L) >= nargs + 1);

lua_pushnil(L);
int rv = lua_gettop(L) - nargs - 1;
lua_insert(L, rv);

// Insert error handler after return value
// Insert error handler
lua_pushcfunction(L, script_error_handler);
int errorhandler = rv + 1;
int errorhandler = lua_gettop(L) - nargs - 1;
lua_insert(L, errorhandler);

// Stack now looks like this:
// ... <return value = nil> <error handler> <table> <arg#1> <arg#2> ... <arg#n>

int table = errorhandler + 1;
int arg = table + 1;

luaL_checktype(L, table, LUA_TTABLE);

// Foreach
lua_pushnil(L);
bool first_loop = true;
while(lua_next(L, table) != 0){
// key at index -2 and value at index -1
luaL_checktype(L, -1, LUA_TFUNCTION);
// Call function
for(int i = 0; i < nargs; i++)
lua_pushvalue(L, arg+i);
if(lua_pcall(L, nargs, 1, errorhandler))
script_error(L);

// Move return value to designated space in stack
// Or pop it
if(first_loop){
// Result of first callback is always moved
lua_replace(L, rv);
first_loop = false;
} else {
// Otherwise, what happens depends on the mode
if(mode == RUN_CALLBACKS_MODE_FIRST)
lua_pop(L, 1);
else if(mode == RUN_CALLBACKS_MODE_LAST)
lua_replace(L, rv);
else if(mode == RUN_CALLBACKS_MODE_AND ||
mode == RUN_CALLBACKS_MODE_AND_SC){
if((bool)lua_toboolean(L, rv) == true &&
(bool)lua_toboolean(L, -1) == false)
lua_replace(L, rv);
else
lua_pop(L, 1);
}
else if(mode == RUN_CALLBACKS_MODE_OR ||
mode == RUN_CALLBACKS_MODE_OR_SC){
if((bool)lua_toboolean(L, rv) == false &&
(bool)lua_toboolean(L, -1) == true)
lua_replace(L, rv);
else
lua_pop(L, 1);
}
else
assert(0);
}
// Insert minetest.run_callbacks between error handler and table
lua_getglobal(L, "minetest");
lua_getfield(L, -1, "run_callbacks");
lua_remove(L, -2);
lua_insert(L, errorhandler + 1);

// Handle short circuit modes
if(mode == RUN_CALLBACKS_MODE_AND_SC &&
(bool)lua_toboolean(L, rv) == false)
break;
else if(mode == RUN_CALLBACKS_MODE_OR_SC &&
(bool)lua_toboolean(L, rv) == true)
break;
// Insert mode after table
lua_pushnumber(L, (int) mode);
lua_insert(L, errorhandler + 3);

// value removed, keep key for next iteration
}

// Remove stuff from stack, leaving only the return value
lua_settop(L, rv);
// Stack now looks like this:
// ... <error handler> <run_callbacks> <table> <mode> <arg#1> <arg#2> ... <arg#n>

// Fix return value in case no callbacks were called
if(first_loop){
if(mode == RUN_CALLBACKS_MODE_AND ||
mode == RUN_CALLBACKS_MODE_AND_SC){
lua_pop(L, 1);
lua_pushboolean(L, true);
}
else if(mode == RUN_CALLBACKS_MODE_OR ||
mode == RUN_CALLBACKS_MODE_OR_SC){
lua_pop(L, 1);
lua_pushboolean(L, false);
}
if (lua_pcall(L, nargs + 2, 1, errorhandler)) {
script_error(L);
}

lua_remove(L, -2); // Remove error handler
}


0 comments on commit a0dce51

Please sign in to comment.