lua-users home
lua-l archive

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


I added an extra field to the metatable to distinguish attributes from
methods like you described.  To define attributes, I extended the
luaL_Reg structure to have a flag indicating if it's a method, a
settable field, a gettable field or both:


struct LuaMethod {
public:
	enum MethodType {
		METHOD = 0,
		GET,
		SET,
		GETSET,
	};

	const char *name;
	lua_CFunction func;
	MethodType type;
};


template <class T>
int Udata<T> :: udata__index(lua_State *L) {
	lua_getfenv(L, 1);				// get userdata environment
	lua_pushvalue(L, 2);
	lua_rawget(L, -2);				// check environment table for field

	if(lua_isnil(L, -1)) {
		lua_getmetatable(L, 1);		// get userdata metatable
		lua_pushvalue(L, 2);
		lua_rawget(L, -2);			// check metatable for field

		if(lua_isnil(L, -1)) {
			lua_pop(L, 1);
			lua_pushstring(L, "getters");
			lua_rawget(L, -2);

			lua_pushvalue(L, 2);
			lua_rawget(L, -2);		// check metatable for field

			// if nil, check in env table
			if (lua_type(L, -1) == LUA_TFUNCTION) { //if(lua_iscfunction(L, -1)) {
				lua_pushvalue(L, 1);
				int err = lua_pcall(L, 1, 1, 0);
				if(err) {
					luaL_error(L, "error indexing %s.%s: %s\n",
											T::name,
											lua_tostring(L, 2),
											lua_tostring(L, -1));
					lua_pop(L, 1);
					return 0;
				}
			}
		}
	}

	return 1;
}


Here's the full source code:
http://www.mat.ucsb.edu/projects/luaAV/browser/branches/luaav3/libluaav/include/luaav_udata.hpp

wes


On Thu, Apr 22, 2010 at 12:27 AM, Ted Unangst <ted.unangst@gmail.com> wrote:
> This seems obvious, but I can't find the right info.  I have a C
> module that exports a 'class' to Lua that has some methods and fields.
>  (It's an image library, for context).
>
> The first thing I did was newmetatable, pushvalue, setfield(-2,
> "__index"), register(L, NULL, methods).  Basically, by the book.  That
> worked great for the methods:
>
> img = GetImage()
> img:resize(x, y)
> img:makepretty() -- whatever
>
> But in order to get access to the width and height, I needed to use
> getters ("img:width()", as a call) which are annoying.  I want
> "img.width" to work.
>
> Currently, I instead wrote my own index method, set that in __index,
> and basically emulate register's behavior by iterating over my method
> array by hand.  Then, if no function matches, I fall back on a series
> of if-else strcmp tests for known field names.  This seems hackish.
>
> Alternatively, I could return a table and hang my userdata off that,
> but it seems prone to accidents.
>
> Am I missing something obvious in the documentation?  Everything I've
> found only talks about adding methods.
>