lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]



Ando Sonenblick wrote:
I have a table (obviously a metatable that implements simple inheritance):

{
    __index = function(table, key)
        return  rawget(XMethods, key) or
                rawget(YMethods, key) or
                rawget(ZMethods, key) end
}

Now, is there a way (from C code) to traverse the table to extract out the
strings "XMethods", "YMethods" and "ZMethods" (without having to resort to
parsing the Lua source code)?

I'm hoping to implement an object inspector that will take and object and
digest it's metatable and display in a UI the contents of the "inherited"
tables, etc...

Hi Ando,

You could make your index event a C function with an upvalue that is a list of tables to search. Then from C, you could retrieve the upvalue and find the names of the list elements in the table of globals.

This should give you some ideas:

print'hello'

one = { a=1,b=2,c=3 }
two = { d=99 }
three = function(t,i) print('did not find',i) return false end

print('one', one)
print('two', two)
print('three', three)

x = setmetatable({}, {__index = search{ one, two, three } })

print(x.a, x.b, x.c, x.d, x.it)


function name(value)
  for n,v in _G do
    if value == v then return n end
  end
end

for i,e in ipairs(searchlist(x)) do print(name(e), e) end


The output from this script is:

hello
one     table: 0xa045d20
two     table: 0xa0464a8
three   function: 0xa045e78
did not find    it
1       2       3       99      false
one     table: 0xa045d20
two     table: 0xa0464a8
three   function: 0xa045e78


where the search and searchlist functions are written in C like so:


#include "lua.h"
#include "lauxlib.h"

static int searcher (lua_State *L) {
  int i=1;
  do {
    lua_settop(L, 2);
    lua_rawgeti(L, lua_upvalueindex(1), i++);
    if (lua_isnil(L, -1)) return 0;  /* end of search list */
    if (lua_isfunction(L, -1)) {
      lua_pushvalue(L, 1);  /* table */
      lua_pushvalue(L, 2);  /* index */
      lua_call(L, 2, 1);
    } else if (lua_istable(L, -1) || lua_isuserdata(L, -1)) {
      if (lua_rawequal(L, 1, -1)) continue;  /* ignore recursive tables */
      lua_pushvalue(L, 2);  /* index */
      lua_gettable(L, -2);
    } else {
luaL_error(L, "search list item must be a function, table or userdata");
    }
  } while (lua_isnil(L, -1));
  return 1;
}

static int search (lua_State *L) {
  luaL_checktype(L, 1, LUA_TTABLE);
  lua_settop(L, 1);
  lua_pushcclosure(L, searcher, 1);
  return 1;
}

static int searchlist (lua_State *L) {
  if (!lua_getmetatable(L, 1)) return 0;  /* no metatable */
  lua_pushliteral(L, "__index");
  lua_gettable(L, -2);
  if (lua_isnil(L, -1)) return 0;         /* no __index event */
  if (!lua_iscfunction(L, -1)) return 0;  /* not a searcher function */
  if (!lua_getupvalue(L, -1, 1)) return 0;  /* no upvalue */
  if (!lua_istable(L, -1)) return 0;      /* upvalue not a table */
  return 1;
}

int search_register (lua_State *L) {
  lua_register(L,"search", search);
  lua_register(L,"searchlist", searchlist);
  return 0;
}

- Peter