Skip to content

Commit

Permalink
lua: refactor to use lua 5.2 syntax for custom metatables
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
cbeck88 committed Dec 26, 2014
1 parent 94006f7 commit 2486b8b
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 100 deletions.
8 changes: 4 additions & 4 deletions src/scripting/game_lua_kernel.cpp
Expand Up @@ -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<t_string *>(lua_touserdata(L, 3));
if (t_string * t_str = static_cast<t_string *> (luaL_testudata(L, 3, tstringKey))) {
v = *t_str;
break;
}
// no break
Expand Down Expand Up @@ -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<t_string *>(lua_touserdata(L, 2));
if (t_string * t_str = static_cast<t_string*> (luaL_testudata(L, 2, tstringKey))) {
v.as_scalar() = *t_str;
break;
}
// no break
Expand Down
140 changes: 62 additions & 78 deletions src/scripting/lua_common.cpp
Expand Up @@ -39,6 +39,10 @@
#include <new> // for operator new
#include <string> // for string, basic_string

static const char * gettextKey = "gettext";
static const char * vconfigKey = "vconfig";
const char * tstringKey = "translatable string";

namespace lua_common {

/**
Expand All @@ -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;
}

Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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";
}
Expand All @@ -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";
}
Expand All @@ -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";
}
Expand All @@ -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);
}


Expand Down Expand Up @@ -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<t_string *>(lua_touserdata(L, index));
break;
if (t_string * tstr = static_cast<t_string *> (luaL_checkudata(L, index, tstringKey))) {
str = *tstr;
break;
} else {
return false;
}
}
default:
return false;
Expand Down Expand Up @@ -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;
Expand All @@ -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<vconfig *> (luaL_checkudata(L, index, vconfigKey))) {
cfg = ptr->get_parsed_config();
return true;
} else {
return false;
cfg = static_cast<vconfig *>(lua_touserdata(L, index))->get_parsed_config();
return true;
}
}
case LUA_TNONE:
case LUA_TNIL:
Expand All @@ -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)
{
Expand All @@ -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);
}
Expand All @@ -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<t_string *>(lua_touserdata(L, -1));
break;
if (t_string * tptr = static_cast<t_string *>(luaL_testudata(L, -1, tstringKey))) {
v = *tptr;
break;
} else {
return_misformed();
}
}
default:
return_misformed();
Expand Down Expand Up @@ -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<vconfig *> (luaL_testudata(L, index, vconfigKey))) {
vcfg = *ptr;
} else {
return false;
vcfg = *static_cast<vconfig *>(lua_touserdata(L, index));
break;
}
case LUA_TNONE:
case LUA_TNIL:
break;
Expand Down
4 changes: 3 additions & 1 deletion src/scripting/lua_common.hpp
Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down
12 changes: 7 additions & 5 deletions src/scripting/lua_gui2.cpp
Expand Up @@ -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
{
Expand All @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down
8 changes: 0 additions & 8 deletions src/scripting/lua_types.cpp
Expand Up @@ -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<void *>(const_cast<char *>(&v_dlgclbkKey));
luatypekey const executeKey = static_cast<void *>(const_cast<char *>(&v_executeKey));
luatypekey const getsideKey = static_cast<void *>(const_cast<char *>(&v_getsideKey));
luatypekey const gettextKey = static_cast<void *>(const_cast<char *>(&v_gettextKey));
luatypekey const gettypeKey = static_cast<void *>(const_cast<char *>(&v_gettypeKey));
luatypekey const getraceKey = static_cast<void *>(const_cast<char *>(&v_getraceKey));
luatypekey const getunitKey = static_cast<void *>(const_cast<char *>(&v_getunitKey));
luatypekey const tstringKey = static_cast<void *>(const_cast<char *>(&v_tstringKey));
luatypekey const unitvarKey = static_cast<void *>(const_cast<char *>(&v_unitvarKey));
luatypekey const ustatusKey = static_cast<void *>(const_cast<char *>(&v_ustatusKey));
luatypekey const vconfigKey = static_cast<void *>(const_cast<char *>(&v_vconfigKey));
luatypekey const currentscriptKey = static_cast<void *>(const_cast<char *>(&v_currentscriptKey));

0 comments on commit 2486b8b

Please sign in to comment.