lua-users home
lua-l archive

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


Am 08.11.2013 22:34 schröbte Geoff Smith:

local a = Foo.new()
a:setx(3)  -- this works as per the example

a.fred = 123  <-- how do I get this to work
print(a.fred) <-- how do I get this to work

Any tips please on how I would change the C api code to make this work in the above example. My failed attempt I added a __newindex and __index into the Foo_meta table, and some associated C code.

The __newindex worked but the __index didn't work as I had overlooked the fact it was already pointing at the methods table.

You put a function instead of the methods table into the `__index` field of the metatable. This function first tries to lookup a given key in the methods table (which can be passed to the function via an upvalue), and then compares the given key with the names of the struct fields to return field values (or the other way around). I use the following code for situations like this ...


    static int dispatch( lua_State* L ) {
      lua_CFunction pindex;
      /* try method table first */
      if( lua_istable( L, lua_upvalueindex( 1 ) ) ) {
        lua_pushvalue( L, 2 ); /* duplicate key */
        lua_rawget( L, lua_upvalueindex( 1 ) );
        if( !lua_isnil( L, -1 ) )
          return 1;
        lua_pop( L, 1 );
      }
      pindex = lua_tocfunction( L, lua_upvalueindex( 2 ) );
      return pindex( L );
    }

    void moon_propindex( lua_State* L, luaL_Reg const* methods,
                         int nups, lua_CFunction pindex ) {
      int top = lua_gettop( L );
      if( methods != NULL ) {
        luaL_checkstack( L, nups + 3, "too many upvalues" );
        lua_newtable( L );
        for( ; methods->func; ++methods ) {
          int i = 0;
          for( i = 0; i < nups; ++i )
            lua_pushvalue( L, top-nups+i+1 );
          lua_pushcclosure( L, methods->func, nups );
          lua_setfield( L, top+1, methods->name );
        }
        if( nups > 0 ) {
          lua_replace( L, top-nups+1 );
          lua_pop( L, nups-1 );
        }
      } else {
        lua_pop( L, nups );
        lua_pushnil( L );
      }
      if( pindex ) {
        lua_pushcfunction( L, pindex );
        lua_pushcclosure( L, dispatch, 2 );
      }
    }

`pindex` is a function that handles the struct fields by doing a series of string comparisons[1] and pushing the corresponding value. The other arguments are the same as for `luaL_setfuncs`[2].

  [1]: http://lua-users.org/lists/lua-l/2013-03/msg00878.html
  [2]: http://www.lua.org/manual/5.2/manual.html#luaL_setfuncs


Thanks for any help

Geoff


Philipp