From 1300b16c1ea233f97a2fe5a7f9be9ab36c2ade8e Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Tue, 16 Jun 2009 15:42:32 +0200 Subject: [PATCH] luaclass: add generic {new,}index meta methods Signed-off-by: Julien Danjou --- common/luaclass.c | 119 ++++++++++++++++++++++++++++++++++++++++++++++ common/luaclass.h | 8 ++++ luaa.h | 16 ------- 3 files changed, 127 insertions(+), 16 deletions(-) diff --git a/common/luaclass.c b/common/luaclass.c index b5fda74dd..a6006a3a8 100644 --- a/common/luaclass.c +++ b/common/luaclass.c @@ -183,4 +183,123 @@ luaA_class_emit_signal(lua_State *L, lua_class_t *lua_class, lua_pop(L, nargs); } +/** Try to use the metatable of an object. + * \param L The Lua VM state. + * \param idxobj The index of the object. + * \param idxfield The index of the field (attribute) to get. + * \return The number of element pushed on stack. + */ +int +luaA_usemetatable(lua_State *L, int idxobj, int idxfield) +{ + /* Get metatable of the object. */ + lua_getmetatable(L, idxobj); + /* Get the field */ + lua_pushvalue(L, idxfield); + lua_rawget(L, -2); + /* Do we have a field like that? */ + if(!lua_isnil(L, -1)) + { + /* Yes, so return it! */ + lua_remove(L, -2); + return 1; + } + /* No, so remove everything. */ + lua_pop(L, 2); + + return 0; +} + +static lua_class_property_t * +lua_class_property_array_getbyid(lua_class_property_array_t *arr, + awesome_token_t id) +{ + lua_class_property_t lookup_prop = { .id = id }; + return lua_class_property_array_lookup(arr, &lookup_prop); +} + +/** Get the class of an object. + * \param L The Lua VM state. + * \param idx The index of the object on the stack. + * \return The class if found, NULL otherwise. + */ +static lua_class_t * +luaA_class_get(lua_State *L, int idx) +{ + int type = luaA_type(L, 1); + + /* Find the class. */ + lua_class_t *class = NULL; + + foreach(classid, luaA_classes) + if(classid->id == type) + { + class = classid->class; + break; + } + + return class; +} + +/** Get a property of a object. + * \param L The Lua VM state. + * \param lua_class The Lua class. + * \param fieldidx The index of the field name. + * \return The object property if found, NULL otherwise. + */ +static lua_class_property_t * +luaA_class_property_get(lua_State *L, lua_class_t *lua_class, int fieldidx) +{ + /* Lookup the property using token */ + size_t len; + const char *attr = luaL_checklstring(L, fieldidx, &len); + awesome_token_t token = a_tokenize(attr, len); + + return lua_class_property_array_getbyid(&lua_class->properties, token); +} + +/** Generic index meta function for objects. + * \param L The Lua VM state. + * \return The number of elements pushed on stack. + */ +int +luaA_class_index(lua_State *L) +{ + /* Try to use metatable first. */ + if(luaA_usemetatable(L, 1, 2)) + return 1; + + lua_class_t *class = luaA_class_get(L, 1); + + lua_class_property_t *prop = luaA_class_property_get(L, class, 2); + + /* Property does exist and has an index callback */ + if(prop && prop->index) + return prop->index(L, luaL_checkudata(L, 1, class->name)); + + return 0; +} + +/** Generic newindex meta function for objects. + * \param L The Lua VM state. + * \return The number of elements pushed on stack. + */ +int +luaA_class_newindex(lua_State *L) +{ + /* Try to use metatable first. */ + if(luaA_usemetatable(L, 1, 2)) + return 1; + + lua_class_t *class = luaA_class_get(L, 1); + + lua_class_property_t *prop = luaA_class_property_get(L, class, 2); + + /* Property does exist and has a newindex callback */ + if(prop && prop->newindex) + return prop->newindex(L, luaL_checkudata(L, 1, class->name)); + + return 0; +} + // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 diff --git a/common/luaclass.h b/common/luaclass.h index 6a6b2ebb4..5d01ca170 100644 --- a/common/luaclass.h +++ b/common/luaclass.h @@ -69,6 +69,10 @@ void luaA_class_setup(lua_State *, lua_class_t *, const char *, lua_class_alloca void luaA_class_add_property(lua_class_t *, awesome_token_t, const char *, lua_class_propfunc_t, lua_class_propfunc_t, lua_class_propfunc_t); +int luaA_usemetatable(lua_State *, int, int); +int luaA_class_index(lua_State *); +int luaA_class_newindex(lua_State *); + #define LUA_CLASS_FUNCS(prefix, lua_class) \ static inline int \ luaA_##prefix##_class_add_signal(lua_State *L) \ @@ -98,6 +102,10 @@ void luaA_class_add_property(lua_class_t *, awesome_token_t, const char *, { "remove_signal", luaA_##class##_class_remove_signal }, \ { "emit_signal", luaA_##class##_class_emit_signal }, +#define LUA_CLASS_META \ + { "__index", luaA_class_index }, \ + { "__newindex", luaA_class_newindex }, + #endif // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 diff --git a/luaa.h b/luaa.h index e6ef709fe..0912c85a1 100644 --- a/luaa.h +++ b/luaa.h @@ -118,22 +118,6 @@ luaA_pusharea(lua_State *L, area_t geometry) return 1; } -static inline int -luaA_usemetatable(lua_State *L, int idxobj, int idxfield) -{ - lua_getmetatable(L, idxobj); - lua_pushvalue(L, idxfield); - lua_rawget(L, -2); - if(!lua_isnil(L, -1)) - { - lua_remove(L, -2); - return 1; - } - lua_pop(L, 2); - - return 0; -} - /** Register an Lua object. * \param L The Lua stack. * \param idx Index of the object in the stack.