From 2486b8ba4bcef056fb523d91f4a8445b48aef685 Mon Sep 17 00:00:00 2001 From: Chris Beck Date: Thu, 25 Dec 2014 23:58:00 -0500 Subject: [PATCH] lua: refactor to use lua 5.2 syntax for custom metatables In lua 5.0, the preferred way to define custom metatables is to use registry keys defined by pushing pointers as lightuserdata to lua. (These pointers can be pointers to arbitrary constant objects, as long as they are unique.) In lua 5.2, the preferred way is to use constant strings as the registry indices, and several lua API functions are introduced: "luaL_newmetatable, luaL_setmetatable, luaL_checkudata, luaL_testudata" which greatly simplify the operations for creating the metatable, assigning it to a userdata, and checking if the userdata has that type. This commit switches over the keys associated to textdomains, translatable strings, vconfigs, and lua gui2 dialogs to use the new style, and simplifies some of the implementation details in the process. For instance, luaW_toconfig no longer has to have an optional argument to an index on the stack where the tstring metatable is... these details are handled by the lua API instead. --- src/scripting/game_lua_kernel.cpp | 8 +- src/scripting/lua_common.cpp | 140 +++++++++++++----------------- src/scripting/lua_common.hpp | 4 +- src/scripting/lua_gui2.cpp | 12 +-- src/scripting/lua_types.cpp | 8 -- src/scripting/lua_types.hpp | 4 - 6 files changed, 76 insertions(+), 100 deletions(-) diff --git a/src/scripting/game_lua_kernel.cpp b/src/scripting/game_lua_kernel.cpp index 0ca4b57c3dff..27d6cffeae46 100644 --- a/src/scripting/game_lua_kernel.cpp +++ b/src/scripting/game_lua_kernel.cpp @@ -483,8 +483,8 @@ static int impl_unit_variables_set(lua_State *L) v = lua_tostring(L, 3); break; case LUA_TUSERDATA: - if (luaW_hasmetatable(L, 3, tstringKey)) { - v = *static_cast(lua_touserdata(L, 3)); + if (t_string * t_str = static_cast (luaL_testudata(L, 3, tstringKey))) { + v = *t_str; break; } // no break @@ -777,8 +777,8 @@ int game_lua_kernel::intf_set_variable(lua_State *L) v.as_scalar() = lua_tostring(L, 2); break; case LUA_TUSERDATA: - if (luaW_hasmetatable(L, 2, tstringKey)) { - v.as_scalar() = *static_cast(lua_touserdata(L, 2)); + if (t_string * t_str = static_cast (luaL_testudata(L, 2, tstringKey))) { + v.as_scalar() = *t_str; break; } // no break diff --git a/src/scripting/lua_common.cpp b/src/scripting/lua_common.cpp index 8b8c5c25f259..b6e88c330891 100644 --- a/src/scripting/lua_common.cpp +++ b/src/scripting/lua_common.cpp @@ -39,6 +39,10 @@ #include // for operator new #include // for string, basic_string +static const char * gettextKey = "gettext"; +static const char * vconfigKey = "vconfig"; +const char * tstringKey = "translatable string"; + namespace lua_common { /** @@ -65,13 +69,11 @@ int intf_textdomain(lua_State *L) { size_t l; char const *m = luaL_checklstring(L, 1, &l); + void *p = lua_newuserdata(L, l + 1); memcpy(p, m, l + 1); - lua_pushlightuserdata(L - , gettextKey); - lua_rawget(L, LUA_REGISTRYINDEX); - lua_setmetatable(L, -2); + luaL_setmetatable(L, gettextKey); return 1; } @@ -108,17 +110,12 @@ static int impl_tstring_concat(lua_State *L) { // Create a new t_string. t_string *t = new(lua_newuserdata(L, sizeof(t_string))) t_string; - - lua_pushlightuserdata(L - , tstringKey); - - lua_rawget(L, LUA_REGISTRYINDEX); + luaL_setmetatable(L, tstringKey); // Append both arguments to t. tstring_concat_aux(L, *t, 1); tstring_concat_aux(L, *t, 2); - lua_setmetatable(L, -2); return 1; } @@ -159,15 +156,11 @@ static int impl_vconfig_get(lua_State *L) unsigned pos = lua_tointeger(L, 2) - 1; if (pos >= len) return 0; std::advance(i, pos); + lua_createtable(L, 2, 0); lua_pushstring(L, i.get_key().c_str()); lua_rawseti(L, -2, 1); - new(lua_newuserdata(L, sizeof(vconfig))) vconfig(i.get_child()); - lua_pushlightuserdata(L - , vconfigKey); - - lua_rawget(L, LUA_REGISTRYINDEX); - lua_setmetatable(L, -2); + luaW_pushvconfig(L, vconfig(i.get_child())); lua_rawseti(L, -2, 2); return 1; } @@ -254,14 +247,16 @@ int intf_tovconfig(lua_State *L) */ std::string register_gettext_metatable(lua_State *L) { - lua_pushlightuserdata(L - , gettextKey); - lua_createtable(L, 0, 2); - lua_pushcfunction(L, lua_common::impl_gettext); - lua_setfield(L, -2, "__call"); + luaL_newmetatable(L, gettextKey); + + static luaL_Reg const callbacks[] = { + { "__call", &impl_gettext}, + { NULL, NULL } + }; + luaL_setfuncs(L, callbacks, 0); + lua_pushstring(L, "message domain"); lua_setfield(L, -2, "__metatable"); - lua_rawset(L, LUA_REGISTRYINDEX); return "Adding gettext metatable...\n"; } @@ -271,18 +266,18 @@ std::string register_gettext_metatable(lua_State *L) */ std::string register_tstring_metatable(lua_State *L) { - lua_pushlightuserdata(L - , tstringKey); - lua_createtable(L, 0, 4); - lua_pushcfunction(L, impl_tstring_concat); - lua_setfield(L, -2, "__concat"); - lua_pushcfunction(L, impl_tstring_collect); - lua_setfield(L, -2, "__gc"); - lua_pushcfunction(L, impl_tstring_tostring); - lua_setfield(L, -2, "__tostring"); + luaL_newmetatable(L, tstringKey); + + static luaL_Reg const callbacks[] = { + { "__concat", &impl_tstring_concat}, + { "__gc", &impl_tstring_collect}, + { "__tostring", &impl_tstring_tostring}, + { NULL, NULL } + }; + luaL_setfuncs(L, callbacks, 0); + lua_pushstring(L, "translatable string"); lua_setfield(L, -2, "__metatable"); - lua_rawset(L, LUA_REGISTRYINDEX); return "Adding tstring metatable...\n"; } @@ -292,18 +287,18 @@ std::string register_tstring_metatable(lua_State *L) */ std::string register_vconfig_metatable(lua_State *L) { - lua_pushlightuserdata(L - , vconfigKey); - lua_createtable(L, 0, 4); - lua_pushcfunction(L, impl_vconfig_collect); - lua_setfield(L, -2, "__gc"); - lua_pushcfunction(L, impl_vconfig_get); - lua_setfield(L, -2, "__index"); - lua_pushcfunction(L, impl_vconfig_size); - lua_setfield(L, -2, "__len"); + luaL_newmetatable(L, vconfigKey); + + static luaL_Reg const callbacks[] = { + { "__gc", &impl_vconfig_collect}, + { "__index", &impl_vconfig_get}, + { "__len", &impl_vconfig_size}, + { NULL, NULL } + }; + luaL_setfuncs(L, callbacks, 0); + lua_pushstring(L, "wml object"); lua_setfield(L, -2, "__metatable"); - lua_rawset(L, LUA_REGISTRYINDEX); return "Adding vconfig metatable...\n"; } @@ -313,21 +308,13 @@ std::string register_vconfig_metatable(lua_State *L) void luaW_pushvconfig(lua_State *L, vconfig const &cfg) { new(lua_newuserdata(L, sizeof(vconfig))) vconfig(cfg); - lua_pushlightuserdata(L - , vconfigKey); - - lua_rawget(L, LUA_REGISTRYINDEX); - lua_setmetatable(L, -2); + luaL_setmetatable(L, vconfigKey); } void luaW_pushtstring(lua_State *L, t_string const &v) { new(lua_newuserdata(L, sizeof(t_string))) t_string(v); - lua_pushlightuserdata(L - , tstringKey); - - lua_rawget(L, LUA_REGISTRYINDEX); - lua_setmetatable(L, -2); + luaL_setmetatable(L, tstringKey); } @@ -384,9 +371,12 @@ bool luaW_totstring(lua_State *L, int index, t_string &str) break; case LUA_TUSERDATA: { - if (!luaW_hasmetatable(L, index, tstringKey)) return false; - str = *static_cast(lua_touserdata(L, index)); - break; + if (t_string * tstr = static_cast (luaL_checkudata(L, index, tstringKey))) { + str = *tstr; + break; + } else { + return false; + } } default: return false; @@ -437,7 +427,7 @@ void luaW_pushconfig(lua_State *L, config const &cfg) #define return_misformed() \ do { lua_settop(L, initial_top); return false; } while (0) -bool luaW_toconfig(lua_State *L, int index, config &cfg, int tstring_meta) +bool luaW_toconfig(lua_State *L, int index, config &cfg) { if (!lua_checkstack(L, LUA_MINSTACK)) return false; @@ -453,10 +443,12 @@ bool luaW_toconfig(lua_State *L, int index, config &cfg, int tstring_meta) break; case LUA_TUSERDATA: { - if (!luaW_hasmetatable(L, index, vconfigKey)) + if (vconfig * ptr = static_cast (luaL_checkudata(L, index, vconfigKey))) { + cfg = ptr->get_parsed_config(); + return true; + } else { return false; - cfg = static_cast(lua_touserdata(L, index))->get_parsed_config(); - return true; + } } case LUA_TNONE: case LUA_TNIL: @@ -465,15 +457,6 @@ bool luaW_toconfig(lua_State *L, int index, config &cfg, int tstring_meta) return false; } - // Get t_string's metatable, so that it can be used later to detect t_string object. - if (!tstring_meta) { - lua_pushlightuserdata(L - , tstringKey); - - lua_rawget(L, LUA_REGISTRYINDEX); - tstring_meta = initial_top + 1; - } - // First convert the children (integer indices). for (int i = 1, i_end = lua_rawlen(L, index); i <= i_end; ++i) { @@ -483,7 +466,7 @@ bool luaW_toconfig(lua_State *L, int index, config &cfg, int tstring_meta) char const *m = lua_tostring(L, -1); if (!m) return_misformed(); lua_rawgeti(L, -2, 2); - if (!luaW_toconfig(L, -1, cfg.add_child(m), tstring_meta)) + if (!luaW_toconfig(L, -1, cfg.add_child(m))) return_misformed(); lua_pop(L, 3); } @@ -506,12 +489,12 @@ bool luaW_toconfig(lua_State *L, int index, config &cfg, int tstring_meta) break; case LUA_TUSERDATA: { - if (!lua_getmetatable(L, -1)) return_misformed(); - bool tstr = lua_rawequal(L, -1, tstring_meta) != 0; - lua_pop(L, 1); - if (!tstr) return_misformed(); - v = *static_cast(lua_touserdata(L, -1)); - break; + if (t_string * tptr = static_cast(luaL_testudata(L, -1, tstringKey))) { + v = *tptr; + break; + } else { + return_misformed(); + } } default: return_misformed(); @@ -546,10 +529,11 @@ bool luaW_tovconfig(lua_State *L, int index, vconfig &vcfg) break; } case LUA_TUSERDATA: - if (!luaW_hasmetatable(L, index, vconfigKey)) + if (vconfig * ptr = static_cast (luaL_testudata(L, index, vconfigKey))) { + vcfg = *ptr; + } else { return false; - vcfg = *static_cast(lua_touserdata(L, index)); - break; + } case LUA_TNONE: case LUA_TNIL: break; diff --git a/src/scripting/lua_common.hpp b/src/scripting/lua_common.hpp index c53a3dbbdc98..750103ae7519 100644 --- a/src/scripting/lua_common.hpp +++ b/src/scripting/lua_common.hpp @@ -34,7 +34,9 @@ namespace lua_common { std::string register_gettext_metatable(lua_State *L); std::string register_tstring_metatable(lua_State *L); std::string register_vconfig_metatable(lua_State *L); + } +extern const char * tstringKey; /** * Pushes a vconfig on the top of the stack. @@ -86,7 +88,7 @@ void luaW_pushconfig(lua_State *L, config const &cfg); * @note If the table has holes in the integer keys or floating-point keys, * some keys will be ignored and the error will go undetected. */ -bool luaW_toconfig(lua_State *L, int index, config &cfg, int tstring_meta = 0); +bool luaW_toconfig(lua_State *L, int index, config &cfg); /** * Converts an optional table or vconfig to a config object. diff --git a/src/scripting/lua_gui2.cpp b/src/scripting/lua_gui2.cpp index 5744f2c73c5c..4933ba35221b 100644 --- a/src/scripting/lua_gui2.cpp +++ b/src/scripting/lua_gui2.cpp @@ -54,6 +54,8 @@ static lg::log_domain log_scripting_lua("scripting/lua"); #define ERR_LUA LOG_STREAM(err, log_scripting_lua) +static const char * dlgclbkKey = "dialog callback"; + namespace { struct scoped_dialog { @@ -75,7 +77,7 @@ namespace { scoped_dialog::scoped_dialog(lua_State *l, gui2::twindow *w) : L(l), prev(current), window(w), callbacks() { - lua_pushlightuserdata(L + lua_pushstring(L , dlgclbkKey); lua_createtable(L, 1, 0); lua_pushvalue(L, -2); @@ -89,7 +91,7 @@ namespace { { delete window; current = prev; - lua_pushlightuserdata(L + lua_pushstring(L , dlgclbkKey); lua_pushvalue(L, -1); lua_rawget(L, LUA_REGISTRYINDEX); @@ -305,7 +307,7 @@ namespace { // helpers of intf_set_dialog_callback() cb = i->second; } lua_State *L = scoped_dialog::current->L; - lua_pushlightuserdata(L + lua_pushstring(L , dlgclbkKey); lua_rawget(L, LUA_REGISTRYINDEX); lua_rawgeti(L, -1, cb); @@ -337,7 +339,7 @@ int intf_set_dialog_callback(lua_State *L) scoped_dialog::callback_map::iterator i = m.find(w); if (i != m.end()) { - lua_pushlightuserdata(L + lua_pushstring(L , dlgclbkKey); lua_rawget(L, LUA_REGISTRYINDEX); lua_pushnil(L); @@ -374,7 +376,7 @@ int intf_set_dialog_callback(lua_State *L) else return luaL_argerror(L, lua_gettop(L), "unsupported widget"); - lua_pushlightuserdata(L + lua_pushstring(L , dlgclbkKey); lua_rawget(L, LUA_REGISTRYINDEX); int n = lua_rawlen(L, -1) + 1; diff --git a/src/scripting/lua_types.cpp b/src/scripting/lua_types.cpp index 340cd1677af1..66320d6dfa05 100644 --- a/src/scripting/lua_types.cpp +++ b/src/scripting/lua_types.cpp @@ -15,29 +15,21 @@ #include "lua_types.hpp" /* Dummy pointer for getting unique keys for Lua's registry. */ -static char const v_dlgclbkKey = 0; static char const v_executeKey = 0; static char const v_getsideKey = 0; -static char const v_gettextKey = 0; static char const v_gettypeKey = 0; static char const v_getraceKey = 0; static char const v_getunitKey = 0; -static char const v_tstringKey = 0; static char const v_unitvarKey = 0; static char const v_ustatusKey = 0; -static char const v_vconfigKey = 0; static char const v_currentscriptKey = 0; -luatypekey const dlgclbkKey = static_cast(const_cast(&v_dlgclbkKey)); luatypekey const executeKey = static_cast(const_cast(&v_executeKey)); luatypekey const getsideKey = static_cast(const_cast(&v_getsideKey)); -luatypekey const gettextKey = static_cast(const_cast(&v_gettextKey)); luatypekey const gettypeKey = static_cast(const_cast(&v_gettypeKey)); luatypekey const getraceKey = static_cast(const_cast(&v_getraceKey)); luatypekey const getunitKey = static_cast(const_cast(&v_getunitKey)); -luatypekey const tstringKey = static_cast(const_cast(&v_tstringKey)); luatypekey const unitvarKey = static_cast(const_cast(&v_unitvarKey)); luatypekey const ustatusKey = static_cast(const_cast(&v_ustatusKey)); -luatypekey const vconfigKey = static_cast(const_cast(&v_vconfigKey)); luatypekey const currentscriptKey = static_cast(const_cast(&v_currentscriptKey)); diff --git a/src/scripting/lua_types.hpp b/src/scripting/lua_types.hpp index a3a9b3d2b5d7..5cf905588b5b 100644 --- a/src/scripting/lua_types.hpp +++ b/src/scripting/lua_types.hpp @@ -19,17 +19,13 @@ typedef void* luatypekey; // i dont want to cast to void* each time .... // a drawback is, that these are now normal static variables wich are initialised at initialisation time (so you shoudn't use these at/before initialisation time). -extern luatypekey const dlgclbkKey; extern luatypekey const executeKey; extern luatypekey const getsideKey; -extern luatypekey const gettextKey; extern luatypekey const gettypeKey; extern luatypekey const getraceKey; extern luatypekey const getunitKey; -extern luatypekey const tstringKey; extern luatypekey const unitvarKey; extern luatypekey const ustatusKey; -extern luatypekey const vconfigKey; extern luatypekey const currentscriptKey; #endif