lua-users home
lua-l archive

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


Thanks you for the comments.

> A reasonable solution. I would add a bit of syntactic sugar:
> 
> print(object.value)  -- instead of object:getValue()
> object.value = 42   -- instead of object:setValue(42)
> 
> by writing an adequate __index metamethod. The bonus of such 
> a syntax, beyond it's lightness, is abstraction over keys. 
> That is, you can use object[key] where key varies programmatically.

I haven't had any luck attempting to do the above. My object is userdata
and if I attempt to access a field on the userdata with the '.' it
errors with the following -

	error : [string "Controls.Inputs[1].value = 1111"]:1: attempt to
index field '?' (a userdata value)

I assume there is some issue with the way I'm registering my tables but
I haven't figured out exactly what the problem is. My code is below - if
you have any suggestions they'd be much appreciated.

The script comments were helpful. Not only am I new to embedding lua but
I'm also new to Lua itself. Thanks.

John



#include <iostream>
#include <lua/lauxlib.h>
#include <lua/lualib.h>
#include <lua/lua.h>

const char* MyObjectID = "Test.Object";
const char* MyObjectClass = "Object";

struct MyObject
{
  double value;
  MyObject() : value( rand() )
  {
  }
  double get_value() { return value; }
  void set_value( double d ) { value = d; }
};

static int getValue( lua_State* L )
{
  MyObject* obj = *(MyObject**)luaL_checkudata(L,1, MyObjectID);;
  lua_pushnumber(L,obj->value);
  return 1;
}

static int setValue( lua_State* L )
{
  MyObject* obj = *(MyObject**)luaL_checkudata(L,1, MyObjectID);;
  obj->value = luaL_checknumber(L,2);
  return 1;
}

static int index( lua_State* L )
{
	const char* key = luaL_checkstring(L, 2);
  std::cout << "in __index, key is " << key << std::endl;
	lua_getmetatable(L, 1);
	lua_getfield(L, -1, key);
  // Either key is name of a method in the metatable
	if(!lua_isnil(L, -1))
		return 1;
	// ... or its a field access - do something based on field name
here ...
  std::cout << "field access ahoy!" << std::endl;
  return 1;
}

static const struct luaL_reg MyObjectInstanceMethods[] = 
{
  { "getValue", getValue },
  { "setValue", setValue },
  { "__index", index },
  {NULL,NULL}
};


int luaMyObjectOpen( lua_State* lua )
{
  // register metatable for MyObject 
  luaL_newmetatable( lua, MyObjectID );
  lua_pushvalue( lua, -1 ); 
  lua_setfield( lua, -1, "__index");
  luaL_register(lua, NULL, MyObjectInstanceMethods );
  return 1;
}

void check_status( lua_State* lua, int status )
{
  if( status )
  {
    const char* msg = lua_tostring(lua, -1);
    lua_pop(lua, 1);
    std::cout << "error : " << msg << std::endl;
  }
}

int main( int argc, char** argv ) {
  lua_State* L = luaL_newstate();
  luaL_openlibs(L);
  luaMyObjectOpen(L);
  // add an object
  MyObject** ptr = (MyObject**)lua_newuserdata(L,sizeof(MyObject*));
  *ptr = new MyObject();
  // set metatable
  luaL_getmetatable(L,MyObjectID);
  lua_setmetatable(L,-2);
  lua_setglobal(L,"MyObject");
  // these work
  check_status( L, luaL_dostring( L, "print( MyObject:getValue())" ));
  check_status( L, luaL_dostring( L, "MyObject:setValue(1234)" ));
  // this doesn't work
  check_status( L, luaL_dostring( L, "print( MyObject:Value )" ));
  // or this
  check_status( L, luaL_dostring( L, "print( MyObject.Value )" ));
  // or this
  check_status( L, luaL_dostring( L, "MyObject:Value = 3333" ));
  // or this
  check_status( L, luaL_dostring( L, "MyObject.Value = 3333" ));
  lua_close(L);
  return 0;
}