Merge pull request #507 from CelticMinstrel/lua-vconfig

Lua vconfig iteration
This commit is contained in:
CelticMinstrel 2015-09-30 15:22:53 -04:00
commit 320372d6b8
2 changed files with 151 additions and 8 deletions

View file

@ -39,9 +39,7 @@ end
--! If @a id is not nil, the "id" attribute of the subtag has to match too.
--! The function also returns the index of the subtag in the array.
function helper.get_child(cfg, name, id)
-- ipairs cannot be used on a vconfig object
for i = 1, #cfg do
local v = cfg[i]
for i,v in ipairs(cfg) do
if v[1] == name then
local w = v[2]
if not id or w.id == id then return w, i end
@ -49,19 +47,50 @@ function helper.get_child(cfg, name, id)
end
end
--! Returns the nth subtag of @a cfg with the given @a name.
--! (Indices start at 1, as always with Lua.)
--! The function also returns the index of the subtag in the array.
function helper.get_nth_child(cfg, name, n)
for i,v in ipairs(cfg) do
if v[1] == name then
n = n - 1
if n == 0 then return v[2], i end
end
end
end
--! Returns the number of subtags of @a with the given @a name.
function helper.child_count(cfg, name)
local n = 0
for i,v in ipairs(cfg) do
if v[1] == name then
n = n + 1
end
end
return n
end
--! Returns an iterator over all the subtags of @a cfg with the given @a name.
function helper.child_range(cfg, tag)
local iter, state, i = ipairs(cfg)
local function f(s)
local c
repeat
local i = s.i
c = cfg[i]
i,c = iter(s,i)
if not c then return end
s.i = i + 1
until c[1] == tag
return c[2]
end
return f, { i = 1 }
return f, state
end
--! Returns an array from the subtags of @a cfg with the given @a name
function helper.child_array(cfg, tag)
local result = {}
for val in helper.child_range(cfg, tag) do
table.insert(result, val)
end
return result
end
--! Modifies all the units satisfying the given @a filter.

View file

@ -42,6 +42,8 @@
static const char * gettextKey = "gettext";
static const char * vconfigKey = "vconfig";
static const char * vconfigpairsKey = "vconfig pairs";
static const char * vconfigipairsKey = "vconfig ipairs";
const char * tstringKey = "translatable string";
namespace lua_common {
@ -227,10 +229,105 @@ static int impl_vconfig_size(lua_State *L)
static int impl_vconfig_collect(lua_State *L)
{
vconfig *v = static_cast<vconfig *>(lua_touserdata(L, 1));
v->vconfig::~vconfig();
v->~vconfig();
return 0;
}
/**
* Iterate through the attributes of a vconfig
*/
static int impl_vconfig_pairs_iter(lua_State *L)
{
vconfig vcfg = luaW_checkvconfig(L, 1);
void* p = luaL_checkudata(L, lua_upvalueindex(1), vconfigpairsKey);
config::const_attr_itors& range = *static_cast<config::const_attr_itors*>(p);
if (range.first == range.second) {
return 0;
}
config::attribute value = *range.first++;
lua_pushlstring(L, value.first.c_str(), value.first.length());
luaW_pushscalar(L, vcfg[value.first]);
return 2;
}
/**
* Destroy a vconfig pairs iterator
*/
static int impl_vconfig_pairs_collect(lua_State *L)
{
typedef config::const_attr_itors const_attr_itors;
void* p = lua_touserdata(L, 1);
const_attr_itors* cai = static_cast<const_attr_itors*>(p);
cai->~const_attr_itors();
return 0;
}
/**
* Construct an iterator to iterate through the attributes of a vconfig
*/
static int impl_vconfig_pairs(lua_State *L)
{
static const size_t sz = sizeof(config::const_attr_itors);
vconfig vcfg = luaW_checkvconfig(L, 1);
new(lua_newuserdata(L, sz)) config::const_attr_itors(vcfg.get_config().attribute_range());
luaL_newmetatable(L, vconfigpairsKey);
lua_setmetatable(L, -2);
lua_pushcclosure(L, &impl_vconfig_pairs_iter, 1);
lua_pushvalue(L, 1);
return 2;
}
typedef std::pair<vconfig::all_children_iterator, vconfig::all_children_iterator> vconfig_child_range;
/**
* Iterate through the subtags of a vconfig
*/
static int impl_vconfig_ipairs_iter(lua_State *L)
{
luaW_checkvconfig(L, 1);
int i = luaL_checkinteger(L, 2);
void* p = luaL_checkudata(L, lua_upvalueindex(1), vconfigipairsKey);
vconfig_child_range& range = *static_cast<vconfig_child_range*>(p);
if (range.first == range.second) {
return 0;
}
std::pair<std::string, vconfig> value = *range.first++;
lua_pushinteger(L, i + 1);
lua_createtable(L, 2, 0);
lua_pushlstring(L, value.first.c_str(), value.first.length());
lua_rawseti(L, -2, 1);
luaW_pushvconfig(L, value.second);
lua_rawseti(L, -2, 2);
return 2;
}
/**
* Destroy a vconfig ipairs iterator
*/
static int impl_vconfig_ipairs_collect(lua_State *L)
{
void* p = lua_touserdata(L, 1);
vconfig_child_range* vcr = static_cast<vconfig_child_range*>(p);
vcr->~vconfig_child_range();
return 0;
}
/**
* Construct an iterator to iterate through the subtags of a vconfig
*/
static int impl_vconfig_ipairs(lua_State *L)
{
static const size_t sz = sizeof(vconfig_child_range);
vconfig cfg = luaW_checkvconfig(L, 1);
new(lua_newuserdata(L, sz)) vconfig_child_range(cfg.ordered_begin(), cfg.ordered_end());
luaL_newmetatable(L, vconfigipairsKey);
lua_setmetatable(L, -2);
lua_pushcclosure(L, &impl_vconfig_ipairs_iter, 1);
lua_pushvalue(L, 1);
lua_pushinteger(L, 0);
return 3;
}
/**
* Creates a vconfig containing the WML table.
* - Arg 1: WML table.
@ -294,12 +391,29 @@ std::string register_vconfig_metatable(lua_State *L)
{ "__gc", &impl_vconfig_collect},
{ "__index", &impl_vconfig_get},
{ "__len", &impl_vconfig_size},
{ "__pairs", &impl_vconfig_pairs},
{ "__ipairs", &impl_vconfig_ipairs},
{ NULL, NULL }
};
luaL_setfuncs(L, callbacks, 0);
lua_pushstring(L, "wml object");
lua_setfield(L, -2, "__metatable");
// Metatables for the iterator userdata
// I don't bother setting __metatable because this
// userdata is only ever stored in the iterator's
// upvalues, so it's never visible to the user.
luaL_newmetatable(L, vconfigpairsKey);
lua_pushstring(L, "__gc");
lua_pushcfunction(L, &impl_vconfig_pairs_collect);
lua_rawset(L, -3);
luaL_newmetatable(L, vconfigipairsKey);
lua_pushstring(L, "__gc");
lua_pushcfunction(L, &impl_vconfig_ipairs_collect);
lua_rawset(L, -3);
return "Adding vconfig metatable...\n";
}