Merge pull request #507 from CelticMinstrel/lua-vconfig
Lua vconfig iteration
This commit is contained in:
commit
320372d6b8
2 changed files with 151 additions and 8 deletions
|
@ -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.
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue