[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: USERDATA getters, setters and methods requirement
- From: Wesley Smith <wesley.hoke@...>
- Date: Wed, 5 Jan 2011 12:43:18 -0800
I've implemented attributes with the following metamethods and setup code:
usr_attr_mt(
lua_State *L,
luaL_reg *methods,
luaL_reg *getters,
luaL_reg *setters
) {
for(int i=0; methods[i].name; i++) {
lua_pushcfunction(L, methods[i].func);
lua_setfield(L, -2, methods[i].name);
}
lua_newtable(L);
if(getters) {
for(int i=0; getters[i].name; i++) {
lua_pushcfunction(L, getters[i].func);
lua_setfield(L, -2, getters[i].name);
}
}
lua_setfield(L, -2, "__getters");
lua_newtable(L);
if(setters) {
for(int i=0; setters[i].name; i++) {
lua_pushcfunction(L, setters[i].func);
lua_setfield(L, -2, setters[i].name);
}
}
lua_setfield(L, -2, "__setters");
}
usr_attr_index(lua_State *L) {
// first check metatable:
lua_getmetatable(L, 1);
lua_pushvalue(L, 2);
lua_rawget(L, -2);
if(lua_isnil(L, -1)) {
lua_pop(L, 1); // bad result; but leave metatable there...
// next try __getters:
lua_pushstring(L, "__getters");
lua_rawget(L, -2);
lua_pushvalue(L, 2);
lua_rawget(L, -2);
if(lua_type(L, -1) == LUA_TFUNCTION) {
lua_pushvalue(L, 1);
int err = lua_pcall(L, 1, 1, 0);
if(err) {
luaL_error(L, "error indexing %s.%s: %s\n",
lua_tostring(L, 1),
lua_tostring(L, 2),
lua_tostring(L, -1));
}
} else {
lua_pop(L, 3); // non-getter, __getters, metatable
// try fenv
lua_getfenv(L, 1);
lua_pushvalue(L, 2);
lua_rawget(L, -2);
}
}
return 1;
}
usr_attr_newindex(lua_State *L) {
// find setter:
lua_getmetatable(L, 1);
lua_pushstring(L, "__setters");
lua_rawget(L, -2);
lua_pushvalue(L, 2);
lua_rawget(L, -2);
// call setter:
if(lua_type(L, -1) == LUA_TFUNCTION) {
lua_pushvalue(L, 1);
lua_pushvalue(L, 3);
int err = lua_pcall(L, 2, 0, 0);
if(err) {
luaL_error(L, "error indexing %s.%s: %s\n",
lua_tostring(L, 1),
lua_tostring(L, 2),
lua_tostring(L, -1));
}
} else {
lua_pop(L, 1); // non-setter
}
lua_pop(L, 2); // __setters, metatable
// store the value in the fenv:
lua_getfenv(L, 1);
lua_pushvalue(L, 2);
lua_pushvalue(L, 3);
lua_rawset(L, -3);
lua_pop(L, 1); // fenv
return 0;
}