Wesley- Your code looks solid and I'm able to implement with minor edits to deal with accessing userdata 'environments' in Lua 5.2 alpha. Thank you very much!
Gaspard- Your Lua code confirmed what I was doing wrong all along. Thanks to you as well!
The major point I was missing is when meta.__index is passed the userdata and function key, I didn't connect to the fact I was only needing to return the function and not actually call the function. Now I understand why VARGS were never present...
In hindsight, the Lua Reference Manual explained [via gettable_event] everything - a captivating document indeed.
Now for some badly needed sleep ;)
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; }
|