From 80016575cd71a2dede4593a0a6373d17b0683d68 Mon Sep 17 00:00:00 2001 From: Ilari Liusvaara Date: Sat, 20 Oct 2012 10:45:56 +0300 Subject: [PATCH] Lua: Clean up callback code --- include/library/lua.hpp | 103 +++++++++++++++++++++++++++++ src/lua/lua.cpp | 171 ++++++++++++------------------------------------ 2 files changed, 146 insertions(+), 128 deletions(-) diff --git a/include/library/lua.hpp b/include/library/lua.hpp index cf8f1859..0d990c34 100644 --- a/include/library/lua.hpp +++ b/include/library/lua.hpp @@ -19,6 +19,92 @@ struct lua_function; class lua_state { public: + template struct _store_tag + { + T& addr; + T val; + _store_tag(T& a, T v) : addr(a), val(v) {} + }; + template static struct _store_tag store_tag(T& a, T v) { return _store_tag(a, v); } + template struct _numeric_tag + { + T val; + _numeric_tag(T v) : val(v) {} + }; + template static struct _numeric_tag numeric_tag(T v) { return _numeric_tag(v); } + template struct _fnptr_tag + { + int(*fn)(lua_state& L, T v); + T val; + _fnptr_tag(int (*f)(lua_state& L, T v), T v) : fn(f), val(v) {} + }; + template static struct _fnptr_tag fnptr_tag(int (*f)(lua_state& L, T v), T v) + { + return _fnptr_tag(f, v); + } + template struct _fn_tag + { + T fn; + _fn_tag(T f) : fn(f) {} + }; + template static struct _fn_tag fn_tag(T v) { return _fn_tag(v); } + struct boolean_tag { bool val; boolean_tag(bool v) : val(v) {}}; + struct string_tag { std::string val; string_tag(const std::string& v) : val(v) {}}; +private: + template void _callback(int argc, _store_tag tag, T... args) + { + tag.addr = tag.val; + _callback(argc, args...); + tag.addr = NULL; + } + + template void _callback(int argc, boolean_tag tag, T... args) + { + pushboolean(tag.val); + _callback(argc + 1, args...); + } + + template void _callback(int argc, string_tag tag, T... args) + { + pushlstring(tag.val.c_str(), tag.val.length()); + _callback(argc + 1, args...); + } + + template void _callback(int argc, _numeric_tag tag, T... args) + { + pushnumber(tag.val); + _callback(argc + 1, args...); + } + + template void _callback(int argc, _fnptr_tag tag, T... args) + { + int extra = tag.fn(*this, tag.val); + _callback(argc + extra, args...); + } + + template void _callback(int argc, _fn_tag tag, T... args) + { + int extra = tag.fn(*this); + _callback(argc + extra, args...); + } + + void _callback(int argc) + { + int r = pcall(argc, 0, 0); + if(r == LUA_ERRRUN) { + (stringfmt() << "Error running Lua callback: " << tostring(-1)).throwex(); + pop(1); + } + if(r == LUA_ERRMEM) { + (stringfmt() << "Error running Lua callback: Out of memory").throwex(); + pop(1); + } + if(r == LUA_ERRERR) { + (stringfmt() << "Error running Lua callback: Double Fault???").throwex(); + pop(1); + } + } +public: /** * Create a new state. */ @@ -123,6 +209,23 @@ public: "present").throwex(); value = static_cast(lua_tonumber(lua_handle, argindex)); } +/** + * Do a callback. + * + * Parameter name: The name of the callback. + * Parameter args: Arguments to pass to the callback. + */ + template + void callback(const std::string& name, T... args) + { + getglobal(name.c_str()); + int t = type(-1); + if(t != LUA_TFUNCTION) { + pop(1); + return; + } + _callback(0, args...); + } void pop(int n) { lua_pop(lua_handle, n); } void* newuserdata(size_t size) { return lua_newuserdata(lua_handle, size); } diff --git a/src/lua/lua.cpp b/src/lua/lua.cpp index c2d93c11..e6542db0 100644 --- a/src/lua/lua.cpp +++ b/src/lua/lua.cpp @@ -64,6 +64,12 @@ bool lua_booted_flag = false; namespace { + int push_keygroup_parameters2(lua_state& L, const struct keygroup::parameters* p) + { + push_keygroup_parameters(L, *p); + return 1; + } + bool recursive_flag = false; const char* luareader_fragment = NULL; @@ -80,27 +86,6 @@ namespace } } - bool callback_exists(const char* name) - { - if(recursive_flag) - return false; - LS.getglobal(name); - int t = LS.type(-1); - if(t != LUA_TFUNCTION) - LS.pop(1); - return (t == LUA_TFUNCTION); - } - - void push_string(lua_state& L, const std::string& s) - { - L.pushlstring(s.c_str(), s.length()); - } - - void push_boolean(lua_state& L, bool b) - { - L.pushboolean(b ? 1 : 0); - } - #define TEMPORARY "LUAINTERP_INTERNAL_COMMAND_TEMPORARY" const char* eval_lua_lua = "loadstring(" TEMPORARY ")();"; @@ -150,7 +135,7 @@ namespace void do_eval_lua(lua_state& L, const std::string& c) throw(std::bad_alloc) { - push_string(L, c); + L.pushlstring(c.c_str(), c.length()); L.setglobal(TEMPORARY); luareader_fragment = eval_lua_lua; run_lua_fragment(L); @@ -158,33 +143,27 @@ namespace void do_run_lua(lua_state& L, const std::string& c) throw(std::bad_alloc) { - push_string(L, c); + L.pushlstring(c.c_str(), c.length()); L.setglobal(TEMPORARY); luareader_fragment = run_lua_lua; run_lua_fragment(L); } - void run_lua_cb(lua_state& L, int args) throw() + template void run_callback(T... args) { + if(recursive_flag) + return; recursive_flag = true; - int r = L.pcall(args, 0, 0); - recursive_flag = false; - if(r == LUA_ERRRUN) { - messages << "Error running Lua callback: " << L.tostring(-1) << std::endl; - L.pop(1); - } - if(r == LUA_ERRMEM) { - messages << "Error running Lua callback: Out of memory" << std::endl; - L.pop(1); - } - if(r == LUA_ERRERR) { - messages << "Error running Lua callback: Double Fault???" << std::endl; - L.pop(1); + try { + LS.callback(args...); + } catch(std::exception& e) { + messages << e.what() << std::endl; } if(lua_requests_repaint) { lua_requests_repaint = false; lsnes_cmd.invoke("repaint"); } + recursive_flag = false; } int system_write_error(lua_State* L) @@ -230,152 +209,97 @@ namespace void lua_callback_do_paint(struct lua_render_context* ctx, bool non_synthetic) throw() { - if(!callback_exists("on_paint")) - return; - lua_render_ctx = ctx; - push_boolean(LS, non_synthetic); - run_lua_cb(LS, 1); - lua_render_ctx = NULL; + run_callback("on_paint", lua_state::store_tag(lua_render_ctx, ctx), lua_state::boolean_tag(non_synthetic)); } void lua_callback_do_video(struct lua_render_context* ctx) throw() { - if(!callback_exists("on_video")) - return; - lua_render_ctx = ctx; - run_lua_cb(LS, 0); - lua_render_ctx = NULL; + run_callback("on_video", lua_state::store_tag(lua_render_ctx, ctx)); } void lua_callback_do_reset() throw() { - if(!callback_exists("on_reset")) - return; - run_lua_cb(LS, 0); + run_callback("on_reset"); } void lua_callback_do_frame() throw() { - if(!callback_exists("on_frame")) - return; - run_lua_cb(LS, 0); + run_callback("on_frame"); } void lua_callback_do_rewind() throw() { - if(!callback_exists("on_rewind")) - return; - run_lua_cb(LS, 0); + run_callback("on_rewind"); } void lua_callback_do_idle() throw() { lua_idle_hook_time = 0x7EFFFFFFFFFFFFFFULL; - if(!callback_exists("on_idle")) - return; - run_lua_cb(LS, 0); + run_callback("on_idle"); } void lua_callback_do_timer() throw() { lua_timer_hook_time = 0x7EFFFFFFFFFFFFFFULL; - if(!callback_exists("on_timer")) - return; - run_lua_cb(LS, 0); + run_callback("on_timer"); } void lua_callback_do_frame_emulated() throw() { - if(!callback_exists("on_frame_emulated")) - return; - run_lua_cb(LS, 0); + run_callback("on_frame_emulated"); } void lua_callback_do_readwrite() throw() { - if(!callback_exists("on_readwrite")) - return; - run_lua_cb(LS, 0); + run_callback("on_readwrite"); } void lua_callback_startup() throw() { lua_booted_flag = true; - if(!callback_exists("on_startup")) - return; - run_lua_cb(LS, 0); + run_callback("on_startup"); } void lua_callback_pre_load(const std::string& name) throw() { - if(!callback_exists("on_pre_load")) - return; - push_string(LS, name); - run_lua_cb(LS, 1); + run_callback("on_pre_load", lua_state::string_tag(name)); } void lua_callback_err_load(const std::string& name) throw() { - if(!callback_exists("on_err_load")) - return; - push_string(LS, name); - run_lua_cb(LS, 1); + run_callback("on_err_load", lua_state::string_tag(name)); } void lua_callback_post_load(const std::string& name, bool was_state) throw() { - if(!callback_exists("on_post_load")) - return; - push_string(LS, name); - push_boolean(LS, was_state); - run_lua_cb(LS, 2); + run_callback("on_post_load", lua_state::string_tag(name), lua_state::boolean_tag(was_state)); } void lua_callback_pre_save(const std::string& name, bool is_state) throw() { - if(!callback_exists("on_pre_save")) - return; - push_string(LS, name); - push_boolean(LS, is_state); - run_lua_cb(LS, 2); + run_callback("on_pre_save", lua_state::string_tag(name), lua_state::boolean_tag(is_state)); } void lua_callback_err_save(const std::string& name) throw() { - if(!callback_exists("on_err_save")) - return; - push_string(LS, name); - run_lua_cb(LS, 1); + run_callback("on_err_save", lua_state::string_tag(name)); } void lua_callback_post_save(const std::string& name, bool is_state) throw() { - if(!callback_exists("on_post_save")) - return; - push_string(LS, name); - push_boolean(LS, is_state); - run_lua_cb(LS, 2); + run_callback("on_post_save", lua_state::string_tag(name), lua_state::boolean_tag(is_state)); } void lua_callback_do_input(controller_frame& data, bool subframe) throw() { - if(!callback_exists("on_input")) - return; - lua_input_controllerdata = &data; - push_boolean(LS, subframe); - run_lua_cb(LS, 1); - lua_input_controllerdata = NULL; + run_callback("on_input", lua_state::store_tag(lua_input_controllerdata, &data), + lua_state::boolean_tag(subframe)); } void lua_callback_snoop_input(uint32_t port, uint32_t controller, uint32_t index, short value) throw() { - if(!callback_exists("on_snoop")) - return; - LS.pushnumber(port); - LS.pushnumber(controller); - LS.pushnumber(index); - LS.pushnumber(value); - run_lua_cb(LS, 4); + run_callback("on_snoop", lua_state::numeric_tag(port), lua_state::numeric_tag(controller), + lua_state::numeric_tag(index), lua_state::numeric_tag(value)); } namespace @@ -411,18 +335,12 @@ namespace void lua_callback_quit() throw() { - if(!callback_exists("on_quit")) - return; - run_lua_cb(LS, 0); + run_callback("on_quit"); } void lua_callback_keyhook(const std::string& key, const struct keygroup::parameters& p) throw() { - if(!callback_exists("on_keyhook")) - return; - LS.pushstring(key.c_str()); - push_keygroup_parameters(LS, p); - run_lua_cb(LS, 2); + run_callback("on_keyhook", lua_state::string_tag(key), lua_state::fnptr_tag(push_keygroup_parameters2, &p)); } void init_lua(bool soft) throw() @@ -469,26 +387,23 @@ void lua_callback_do_unsafe_rewind(const std::vector& save, uint64_t secs, lua_unsaferewind* u2 = reinterpret_cast*>(u)->object(); //Load. try { - if(callback_exists("on_pre_rewind")) - run_lua_cb(LS, 0); + run_callback("on_pre_rewind"); mainloop_restore_state(u2->state, u2->secs, u2->ssecs); mov.fast_load(u2->frame, u2->ptr, u2->lag, u2->pollcounters); - if(callback_exists("on_post_rewind")) - run_lua_cb(LS, 0); + run_callback("on_post_rewind"); } catch(...) { return; } } else { //Save - if(callback_exists("on_set_rewind")) { + run_callback("on_set_rewind", lua_state::fn_tag([save, secs, ssecs, &mov](lua_state& L) -> int { lua_unsaferewind* u2 = lua_class::create(LS); u2->state = save; u2->secs = secs, u2->ssecs = ssecs; mov.fast_save(u2->frame, u2->ptr, u2->lag, u2->pollcounters); - run_lua_cb(LS, 1); - } - + return 1; + })); } } -- 2.11.4.GIT