Problem with userdata (metatable)

classic Classic list List threaded Threaded
13 messages Options
Reply | Threaded
Open this post in threaded view
|

Problem with userdata (metatable)

Anders Bergh-2
Hi!

I'm using Lua 5.1 and I've been trying to add my own userdata type. It
works except I couldn't get methods working. I've been reading the
chapter in the first edition of pil and
http://lua-users.org/wiki/UserDataWithPointerExample.

Here's the code I use:

static const luaL_reg llua_user_f[] = {
  /* Functions */
  {"FindByNick", llua_user_FindByNick},

  /* Methods */
  {"GetNick", llua_user_GetNick},
  {NULL, NULL}
};

/* Metatable */
static const luaL_reg llua_user_m[] = {
  {"__tostring", llua_user_tostring},
  {NULL, NULL}
};

int lluaopen_user (lua_State *L) {
  luaL_openlib(L, "user", llua_user_f, 0);
  luaL_newmetatable(L, TYPE);
  luaL_openlib(L, 0, llua_user_m, 0); /* mt */

  lua_pushliteral(L, "__index");
  lua_pushvalue(L, -3);
  lua_rawset(L, -3);

  lua_pushliteral(L, "__metatable");
  lua_pushvalue(L, -3);
  lua_rawset(L, -3);

  lua_pop(L, 1);
  return 1;
}

When I use "user:GetNick()" in Lua, I get the error: attempt to index
field '?' (a nil value).

getmetatable(user) returns nil, tostring(user) returns "user:
0x815598c". What exactly am I doing wrong?

Anders
Reply | Threaded
Open this post in threaded view
|

Re: Problem with userdata (metatable)

Goran Zoricic
I'm not a seasoned Lua veteran (yet ;) ),  but shouldn't you use:

lua_setmetatable(L, -2);

instead of:

...
lua_pushliteral(L, "__metatable");
lua_pushvalue(L, -3);
lua_rawset(L, -3);
...

Cheers,

Goran.

Anders Bergh wrote:

> Hi!
>
> I'm using Lua 5.1 and I've been trying to add my own userdata type. It
> works except I couldn't get methods working. I've been reading the
> chapter in the first edition of pil and
> http://lua-users.org/wiki/UserDataWithPointerExample.
>
> Here's the code I use:
>
> static const luaL_reg llua_user_f[] = {
>  /* Functions */
>  {"FindByNick", llua_user_FindByNick},
>
>  /* Methods */
>  {"GetNick", llua_user_GetNick},
>  {NULL, NULL}
> };
>
> /* Metatable */
> static const luaL_reg llua_user_m[] = {
>  {"__tostring", llua_user_tostring},
>  {NULL, NULL}
> };
>
> int lluaopen_user (lua_State *L) {
>  luaL_openlib(L, "user", llua_user_f, 0);
>  luaL_newmetatable(L, TYPE);
>  luaL_openlib(L, 0, llua_user_m, 0); /* mt */
>
>  lua_pushliteral(L, "__index");
>  lua_pushvalue(L, -3);
>  lua_rawset(L, -3);
>
>  lua_pushliteral(L, "__metatable");
>  lua_pushvalue(L, -3);
>  lua_rawset(L, -3);
>
>  lua_pop(L, 1);
>  return 1;
> }
>
> When I use "user:GetNick()" in Lua, I get the error: attempt to index
> field '?' (a nil value).
>
> getmetatable(user) returns nil, tostring(user) returns "user:
> 0x815598c". What exactly am I doing wrong?
>
> Anders

--
The absolute law of the universe: everything depends
Reply | Threaded
Open this post in threaded view
|

Re: Problem with userdata (metatable)

Anders Bergh-2
I tried it, I still have the same problem. :(

Anders

On 4/12/06, Goran Zoricic <[hidden email]> wrote:

> I'm not a seasoned Lua veteran (yet ;) ),  but shouldn't you use:
>
> lua_setmetatable(L, -2);
>
> instead of:
>
> ...
> lua_pushliteral(L, "__metatable");
> lua_pushvalue(L, -3);
> lua_rawset(L, -3);
> ...
>
> Cheers,
>
> Goran.
>
> Anders Bergh wrote:
> > Hi!
> >
> > I'm using Lua 5.1 and I've been trying to add my own userdata type. It
> > works except I couldn't get methods working. I've been reading the
> > chapter in the first edition of pil and
> > http://lua-users.org/wiki/UserDataWithPointerExample.
> >
> > Here's the code I use:
> >
> > static const luaL_reg llua_user_f[] = {
> >  /* Functions */
> >  {"FindByNick", llua_user_FindByNick},
> >
> >  /* Methods */
> >  {"GetNick", llua_user_GetNick},
> >  {NULL, NULL}
> > };
> >
> > /* Metatable */
> > static const luaL_reg llua_user_m[] = {
> >  {"__tostring", llua_user_tostring},
> >  {NULL, NULL}
> > };
> >
> > int lluaopen_user (lua_State *L) {
> >  luaL_openlib(L, "user", llua_user_f, 0);
> >  luaL_newmetatable(L, TYPE);
> >  luaL_openlib(L, 0, llua_user_m, 0); /* mt */
> >
> >  lua_pushliteral(L, "__index");
> >  lua_pushvalue(L, -3);
> >  lua_rawset(L, -3);
> >
> >  lua_pushliteral(L, "__metatable");
> >  lua_pushvalue(L, -3);
> >  lua_rawset(L, -3);
> >
> >  lua_pop(L, 1);
> >  return 1;
> > }
> >
> > When I use "user:GetNick()" in Lua, I get the error: attempt to index
> > field '?' (a nil value).
> >
> > getmetatable(user) returns nil, tostring(user) returns "user:
> > 0x815598c". What exactly am I doing wrong?
> >
> > Anders
>
> --
> The absolute law of the universe: everything depends
>
Reply | Threaded
Open this post in threaded view
|

RE: Problem with userdata (metatable)

jdarling
In reply to this post by Anders Bergh-2
Since you in C/C++ take a look at how LUNA is doing things.  I'm no
vertran myself, but I have had some problems with methods in Delphi
(actually enough that I believe I see your problem).

You need to track your methods table, object meta table, and object
table.  For example some working code of mine (note again Delphi not C)
is:

procedure RegisterMyClass(LuaScript:TLUAWrapper);
var
  MetaTable,
  MethodTable,
  Methods : Integer;
begin
  lua_newtable(LuaScript.LuaState);
  Methods := lua_gettop(LuaScript.LuaState);

// Lua<#ClassName#>ClassName - represents the class name in text
  luaL_newmetatable(LuaScript.LuaState, Lua<#ClassName#>ClassName);
  MetaTable := lua_gettop(LuaScript.LuaState);
 
  lua_pushstring(LuaScript.LuaState, Lua<#ClassName#>ClassName);
  lua_pushvalue(LuaScript.LuaState, Methods);
  lua_settable(LuaScript.LuaState, LUA_GLOBALSINDEX);

  lua_pushliteral(LuaScript.LuaState, '__metatable');
  lua_pushvalue(LuaScript.LuaState, Methods);
  lua_settable(LuaScript.LuaState, MetaTable);

  lua_pushliteral(LuaScript.LuaState, '__index');
  lua_pushcfunction(LuaScript.LuaState, index_<#ClassName#>);
  lua_settable(LuaScript.LuaState, MetaTable);

  lua_pushliteral(LuaScript.LuaState, '__newindex');
  lua_pushcfunction(LuaScript.LuaState, newindex_<#ClassName#>);
  lua_settable(LuaScript.LuaState, MetaTable);

  lua_pushliteral(LuaScript.LuaState, '__gc');
  lua_pushcfunction(LuaScript.LuaState, gc_<#ClassName#>);
  lua_settable(LuaScript.LuaState, MetaTable);

  lua_newtable(LuaScript.LuaState);
  MethodTable := lua_gettop(LuaScript.LuaState);
  lua_pushliteral(LuaScript.LuaState, '__call');
  lua_pushcfunction(LuaScript.LuaState, new_<#ClassName#>);
  lua_pushliteral(LuaScript.LuaState, '__new');
  lua_pushvalue(LuaScript.LuaState, -2);
  lua_settable(LuaScript.LuaState, Methods);
  lua_settable(LuaScript.LuaState, MethodTable);
  lua_setmetatable(LuaScript.LuaState, Methods);

// for each method that you want to register
  lua_pushcfunction(LuaScript.LuaState, lua<#ClassName#><#MethodName#>);
  lua_settable(LuaScript.LuaState, Methods);
// end of for each method

  lua_pop(LuaScript.LuaState, 2);
end;

 - Jeremy

"Help I suffer from the oxymoron Corporate Security."


> -------- Original Message --------
> Subject: Problem with userdata (metatable)
> From: "Anders Bergh" <[hidden email]>
> Date: Wed, April 12, 2006 8:25 am
> To: "Lua list" <[hidden email]>
>
> Hi!
>
> I'm using Lua 5.1 and I've been trying to add my own userdata type. It
> works except I couldn't get methods working. I've been reading the
> chapter in the first edition of pil and
> http://lua-users.org/wiki/UserDataWithPointerExample.
>
> Here's the code I use:
>
> static const luaL_reg llua_user_f[] = {
>   /* Functions */
>   {"FindByNick", llua_user_FindByNick},
>
>   /* Methods */
>   {"GetNick", llua_user_GetNick},
>   {NULL, NULL}
> };
>
> /* Metatable */
> static const luaL_reg llua_user_m[] = {
>   {"__tostring", llua_user_tostring},
>   {NULL, NULL}
> };
>
> int lluaopen_user (lua_State *L) {
>   luaL_openlib(L, "user", llua_user_f, 0);
>   luaL_newmetatable(L, TYPE);
>   luaL_openlib(L, 0, llua_user_m, 0); /* mt */
>
>   lua_pushliteral(L, "__index");
>   lua_pushvalue(L, -3);
>   lua_rawset(L, -3);
>
>   lua_pushliteral(L, "__metatable");
>   lua_pushvalue(L, -3);
>   lua_rawset(L, -3);
>
>   lua_pop(L, 1);
>   return 1;
> }
>
> When I use "user:GetNick()" in Lua, I get the error: attempt to index
> field '?' (a nil value).
>
> getmetatable(user) returns nil, tostring(user) returns "user:
> 0x815598c". What exactly am I doing wrong?
>
> Anders

Reply | Threaded
Open this post in threaded view
|

Re: Problem with userdata (metatable)

Anders Bergh-2
I'm going to test what you did in your Delphi code, and test it in my
code to see if it works. How come the
http://lua-users.org/wiki/UserDataWithPointerExample example doesn't
work though? Did things change in Lua 5.1?

Anders

On 4/12/06, [hidden email] <[hidden email]> wrote:

> Since you in C/C++ take a look at how LUNA is doing things.  I'm no
> vertran myself, but I have had some problems with methods in Delphi
> (actually enough that I believe I see your problem).
>
> You need to track your methods table, object meta table, and object
> table.  For example some working code of mine (note again Delphi not C)
> is:
>
> procedure RegisterMyClass(LuaScript:TLUAWrapper);
> var
>   MetaTable,
>   MethodTable,
>   Methods : Integer;
> begin
>   lua_newtable(LuaScript.LuaState);
>   Methods := lua_gettop(LuaScript.LuaState);
>
> // Lua<#ClassName#>ClassName - represents the class name in text
>   luaL_newmetatable(LuaScript.LuaState, Lua<#ClassName#>ClassName);
>   MetaTable := lua_gettop(LuaScript.LuaState);
>
>   lua_pushstring(LuaScript.LuaState, Lua<#ClassName#>ClassName);
>   lua_pushvalue(LuaScript.LuaState, Methods);
>   lua_settable(LuaScript.LuaState, LUA_GLOBALSINDEX);
>
>   lua_pushliteral(LuaScript.LuaState, '__metatable');
>   lua_pushvalue(LuaScript.LuaState, Methods);
>   lua_settable(LuaScript.LuaState, MetaTable);
>
>   lua_pushliteral(LuaScript.LuaState, '__index');
>   lua_pushcfunction(LuaScript.LuaState, index_<#ClassName#>);
>   lua_settable(LuaScript.LuaState, MetaTable);
>
>   lua_pushliteral(LuaScript.LuaState, '__newindex');
>   lua_pushcfunction(LuaScript.LuaState, newindex_<#ClassName#>);
>   lua_settable(LuaScript.LuaState, MetaTable);
>
>   lua_pushliteral(LuaScript.LuaState, '__gc');
>   lua_pushcfunction(LuaScript.LuaState, gc_<#ClassName#>);
>   lua_settable(LuaScript.LuaState, MetaTable);
>
>   lua_newtable(LuaScript.LuaState);
>   MethodTable := lua_gettop(LuaScript.LuaState);
>   lua_pushliteral(LuaScript.LuaState, '__call');
>   lua_pushcfunction(LuaScript.LuaState, new_<#ClassName#>);
>   lua_pushliteral(LuaScript.LuaState, '__new');
>   lua_pushvalue(LuaScript.LuaState, -2);
>   lua_settable(LuaScript.LuaState, Methods);
>   lua_settable(LuaScript.LuaState, MethodTable);
>   lua_setmetatable(LuaScript.LuaState, Methods);
>
> // for each method that you want to register
>   lua_pushcfunction(LuaScript.LuaState, lua<#ClassName#><#MethodName#>);
>   lua_settable(LuaScript.LuaState, Methods);
> // end of for each method
>
>   lua_pop(LuaScript.LuaState, 2);
> end;
>
>  - Jeremy
>
> "Help I suffer from the oxymoron Corporate Security."
>
>
> > -------- Original Message --------
> > Subject: Problem with userdata (metatable)
> > From: "Anders Bergh" <[hidden email]>
> > Date: Wed, April 12, 2006 8:25 am
> > To: "Lua list" <[hidden email]>
> >
> > Hi!
> >
> > I'm using Lua 5.1 and I've been trying to add my own userdata type. It
> > works except I couldn't get methods working. I've been reading the
> > chapter in the first edition of pil and
> > http://lua-users.org/wiki/UserDataWithPointerExample.
> >
> > Here's the code I use:
> >
> > static const luaL_reg llua_user_f[] = {
> >   /* Functions */
> >   {"FindByNick", llua_user_FindByNick},
> >
> >   /* Methods */
> >   {"GetNick", llua_user_GetNick},
> >   {NULL, NULL}
> > };
> >
> > /* Metatable */
> > static const luaL_reg llua_user_m[] = {
> >   {"__tostring", llua_user_tostring},
> >   {NULL, NULL}
> > };
> >
> > int lluaopen_user (lua_State *L) {
> >   luaL_openlib(L, "user", llua_user_f, 0);
> >   luaL_newmetatable(L, TYPE);
> >   luaL_openlib(L, 0, llua_user_m, 0); /* mt */
> >
> >   lua_pushliteral(L, "__index");
> >   lua_pushvalue(L, -3);
> >   lua_rawset(L, -3);
> >
> >   lua_pushliteral(L, "__metatable");
> >   lua_pushvalue(L, -3);
> >   lua_rawset(L, -3);
> >
> >   lua_pop(L, 1);
> >   return 1;
> > }
> >
> > When I use "user:GetNick()" in Lua, I get the error: attempt to index
> > field '?' (a nil value).
> >
> > getmetatable(user) returns nil, tostring(user) returns "user:
> > 0x815598c". What exactly am I doing wrong?
> >
> > Anders
>
>
Reply | Threaded
Open this post in threaded view
|

RE: Problem with userdata (metatable)

jdarling
In reply to this post by Anders Bergh-2
No idea, I'm still using Lua 5.0.2 but used the LUNA 5.1 as a reference
point for my wrapper classes.  Hopefully this means that I'm ready for
5.1 when the headers are converted :).

 - Jeremy

"Help I suffer from the oxymoron Corporate Security."


> -------- Original Message --------
> Subject: Re: Problem with userdata (metatable)
> From: "Anders Bergh" <[hidden email]>
> Date: Wed, April 12, 2006 11:17 am
> To: "Lua list" <[hidden email]>
>
> I'm going to test what you did in your Delphi code, and test it in my
> code to see if it works. How come the
> http://lua-users.org/wiki/UserDataWithPointerExample example doesn't
> work though? Did things change in Lua 5.1?
>
> Anders
>
> On 4/12/06, [hidden email] <[hidden email]> wrote:
> > Since you in C/C++ take a look at how LUNA is doing things.  I'm no
> > vertran myself, but I have had some problems with methods in Delphi
> > (actually enough that I believe I see your problem).
> >
> > You need to track your methods table, object meta table, and object
> > table.  For example some working code of mine (note again Delphi not C)
> > is:
> >
> > procedure RegisterMyClass(LuaScript:TLUAWrapper);
> > var
> >   MetaTable,
> >   MethodTable,
> >   Methods : Integer;
> > begin
> >   lua_newtable(LuaScript.LuaState);
> >   Methods := lua_gettop(LuaScript.LuaState);
> >
> > // Lua<#ClassName#>ClassName - represents the class name in text
> >   luaL_newmetatable(LuaScript.LuaState, Lua<#ClassName#>ClassName);
> >   MetaTable := lua_gettop(LuaScript.LuaState);
> >
> >   lua_pushstring(LuaScript.LuaState, Lua<#ClassName#>ClassName);
> >   lua_pushvalue(LuaScript.LuaState, Methods);
> >   lua_settable(LuaScript.LuaState, LUA_GLOBALSINDEX);
> >
> >   lua_pushliteral(LuaScript.LuaState, '__metatable');
> >   lua_pushvalue(LuaScript.LuaState, Methods);
> >   lua_settable(LuaScript.LuaState, MetaTable);
> >
> >   lua_pushliteral(LuaScript.LuaState, '__index');
> >   lua_pushcfunction(LuaScript.LuaState, index_<#ClassName#>);
> >   lua_settable(LuaScript.LuaState, MetaTable);
> >
> >   lua_pushliteral(LuaScript.LuaState, '__newindex');
> >   lua_pushcfunction(LuaScript.LuaState, newindex_<#ClassName#>);
> >   lua_settable(LuaScript.LuaState, MetaTable);
> >
> >   lua_pushliteral(LuaScript.LuaState, '__gc');
> >   lua_pushcfunction(LuaScript.LuaState, gc_<#ClassName#>);
> >   lua_settable(LuaScript.LuaState, MetaTable);
> >
> >   lua_newtable(LuaScript.LuaState);
> >   MethodTable := lua_gettop(LuaScript.LuaState);
> >   lua_pushliteral(LuaScript.LuaState, '__call');
> >   lua_pushcfunction(LuaScript.LuaState, new_<#ClassName#>);
> >   lua_pushliteral(LuaScript.LuaState, '__new');
> >   lua_pushvalue(LuaScript.LuaState, -2);
> >   lua_settable(LuaScript.LuaState, Methods);
> >   lua_settable(LuaScript.LuaState, MethodTable);
> >   lua_setmetatable(LuaScript.LuaState, Methods);
> >
> > // for each method that you want to register
> >   lua_pushcfunction(LuaScript.LuaState, lua<#ClassName#><#MethodName#>);
> >   lua_settable(LuaScript.LuaState, Methods);
> > // end of for each method
> >
> >   lua_pop(LuaScript.LuaState, 2);
> > end;
> >
> >  - Jeremy
> >
> > "Help I suffer from the oxymoron Corporate Security."
> >
> >
> > > -------- Original Message --------
> > > Subject: Problem with userdata (metatable)
> > > From: "Anders Bergh" <[hidden email]>
> > > Date: Wed, April 12, 2006 8:25 am
> > > To: "Lua list" <[hidden email]>
> > >
> > > Hi!
> > >
> > > I'm using Lua 5.1 and I've been trying to add my own userdata type. It
> > > works except I couldn't get methods working. I've been reading the
> > > chapter in the first edition of pil and
> > > http://lua-users.org/wiki/UserDataWithPointerExample.
> > >
> > > Here's the code I use:
> > >
> > > static const luaL_reg llua_user_f[] = {
> > >   /* Functions */
> > >   {"FindByNick", llua_user_FindByNick},
> > >
> > >   /* Methods */
> > >   {"GetNick", llua_user_GetNick},
> > >   {NULL, NULL}
> > > };
> > >
> > > /* Metatable */
> > > static const luaL_reg llua_user_m[] = {
> > >   {"__tostring", llua_user_tostring},
> > >   {NULL, NULL}
> > > };
> > >
> > > int lluaopen_user (lua_State *L) {
> > >   luaL_openlib(L, "user", llua_user_f, 0);
> > >   luaL_newmetatable(L, TYPE);
> > >   luaL_openlib(L, 0, llua_user_m, 0); /* mt */
> > >
> > >   lua_pushliteral(L, "__index");
> > >   lua_pushvalue(L, -3);
> > >   lua_rawset(L, -3);
> > >
> > >   lua_pushliteral(L, "__metatable");
> > >   lua_pushvalue(L, -3);
> > >   lua_rawset(L, -3);
> > >
> > >   lua_pop(L, 1);
> > >   return 1;
> > > }
> > >
> > > When I use "user:GetNick()" in Lua, I get the error: attempt to index
> > > field '?' (a nil value).
> > >
> > > getmetatable(user) returns nil, tostring(user) returns "user:
> > > 0x815598c". What exactly am I doing wrong?
> > >
> > > Anders
> >
> >

Reply | Threaded
Open this post in threaded view
|

Re: Problem with userdata (metatable)

Anders Bergh-2
This is the code that's used in the example:

int Image_register (lua_State *L)
{
  luaL_openlib(L, IMAGE, Image_methods, 0);  /* create methods table,
                                                add it to the globals */
  luaL_newmetatable(L, IMAGE);        /* create metatable for Image,
                                         add it to the Lua registry */
  luaL_openlib(L, 0, Image_meta, 0);  /* fill metatable */
  lua_pushliteral(L, "__index");
  lua_pushvalue(L, -3);               /* dup methods table*/
  lua_rawset(L, -3);                  /* metatable.__index = methods */
  lua_pushliteral(L, "__metatable");
  lua_pushvalue(L, -3);               /* dup methods table*/
  lua_rawset(L, -3);                  /* hide metatable:
                                         metatable.__metatable = methods */
  lua_pop(L, 1);                      /* drop metatable */
  return 1;                           /* return methods on the stack */
}

This is the code I use:

int lluaopen_user (lua_State *L) {
 luaL_openlib(L, "user", llua_user_f, 0);
 luaL_newmetatable(L, TYPE);
 luaL_openlib(L, 0, llua_user_m, 0); /* mt */

 lua_pushliteral(L, "__index");
 lua_pushvalue(L, -3);
 lua_rawset(L, -3);

 lua_pushliteral(L, "__metatable");
 lua_pushvalue(L, -3);
 lua_rawset(L, -3);

 lua_pop(L, 1);
 return 1;
}

TYPE is defined as "L2.user".

The GD binding example code works in 5.1 (the methods work), but they
don't in my code so there must be something I'm doing differently...
but what? Reading your Delphi code didn't really help me (I don't have
a C function for __index, and I couldn't exactly figure out what to do
instead). Should I open the library in a certain way?

Anders

On 4/12/06, [hidden email] <[hidden email]> wrote:

> No idea, I'm still using Lua 5.0.2 but used the LUNA 5.1 as a reference
> point for my wrapper classes.  Hopefully this means that I'm ready for
> 5.1 when the headers are converted :).
>
>  - Jeremy
>
> "Help I suffer from the oxymoron Corporate Security."
>
>
> > -------- Original Message --------
> > Subject: Re: Problem with userdata (metatable)
> > From: "Anders Bergh" <[hidden email]>
> > Date: Wed, April 12, 2006 11:17 am
> > To: "Lua list" <[hidden email]>
> >
> > I'm going to test what you did in your Delphi code, and test it in my
> > code to see if it works. How come the
> > http://lua-users.org/wiki/UserDataWithPointerExample example doesn't
> > work though? Did things change in Lua 5.1?
> >
> > Anders
> >
> > On 4/12/06, [hidden email] <[hidden email]> wrote:
> > > Since you in C/C++ take a look at how LUNA is doing things.  I'm no
> > > vertran myself, but I have had some problems with methods in Delphi
> > > (actually enough that I believe I see your problem).
> > >
> > > You need to track your methods table, object meta table, and object
> > > table.  For example some working code of mine (note again Delphi not C)
> > > is:
> > >
> > > procedure RegisterMyClass(LuaScript:TLUAWrapper);
> > > var
> > >   MetaTable,
> > >   MethodTable,
> > >   Methods : Integer;
> > > begin
> > >   lua_newtable(LuaScript.LuaState);
> > >   Methods := lua_gettop(LuaScript.LuaState);
> > >
> > > // Lua<#ClassName#>ClassName - represents the class name in text
> > >   luaL_newmetatable(LuaScript.LuaState, Lua<#ClassName#>ClassName);
> > >   MetaTable := lua_gettop(LuaScript.LuaState);
> > >
> > >   lua_pushstring(LuaScript.LuaState, Lua<#ClassName#>ClassName);
> > >   lua_pushvalue(LuaScript.LuaState, Methods);
> > >   lua_settable(LuaScript.LuaState, LUA_GLOBALSINDEX);
> > >
> > >   lua_pushliteral(LuaScript.LuaState, '__metatable');
> > >   lua_pushvalue(LuaScript.LuaState, Methods);
> > >   lua_settable(LuaScript.LuaState, MetaTable);
> > >
> > >   lua_pushliteral(LuaScript.LuaState, '__index');
> > >   lua_pushcfunction(LuaScript.LuaState, index_<#ClassName#>);
> > >   lua_settable(LuaScript.LuaState, MetaTable);
> > >
> > >   lua_pushliteral(LuaScript.LuaState, '__newindex');
> > >   lua_pushcfunction(LuaScript.LuaState, newindex_<#ClassName#>);
> > >   lua_settable(LuaScript.LuaState, MetaTable);
> > >
> > >   lua_pushliteral(LuaScript.LuaState, '__gc');
> > >   lua_pushcfunction(LuaScript.LuaState, gc_<#ClassName#>);
> > >   lua_settable(LuaScript.LuaState, MetaTable);
> > >
> > >   lua_newtable(LuaScript.LuaState);
> > >   MethodTable := lua_gettop(LuaScript.LuaState);
> > >   lua_pushliteral(LuaScript.LuaState, '__call');
> > >   lua_pushcfunction(LuaScript.LuaState, new_<#ClassName#>);
> > >   lua_pushliteral(LuaScript.LuaState, '__new');
> > >   lua_pushvalue(LuaScript.LuaState, -2);
> > >   lua_settable(LuaScript.LuaState, Methods);
> > >   lua_settable(LuaScript.LuaState, MethodTable);
> > >   lua_setmetatable(LuaScript.LuaState, Methods);
> > >
> > > // for each method that you want to register
> > >   lua_pushcfunction(LuaScript.LuaState, lua<#ClassName#><#MethodName#>);
> > >   lua_settable(LuaScript.LuaState, Methods);
> > > // end of for each method
> > >
> > >   lua_pop(LuaScript.LuaState, 2);
> > > end;
> > >
> > >  - Jeremy
> > >
> > > "Help I suffer from the oxymoron Corporate Security."
> > >
> > >
> > > > -------- Original Message --------
> > > > Subject: Problem with userdata (metatable)
> > > > From: "Anders Bergh" <[hidden email]>
> > > > Date: Wed, April 12, 2006 8:25 am
> > > > To: "Lua list" <[hidden email]>
> > > >
> > > > Hi!
> > > >
> > > > I'm using Lua 5.1 and I've been trying to add my own userdata type. It
> > > > works except I couldn't get methods working. I've been reading the
> > > > chapter in the first edition of pil and
> > > > http://lua-users.org/wiki/UserDataWithPointerExample.
> > > >
> > > > Here's the code I use:
> > > >
> > > > static const luaL_reg llua_user_f[] = {
> > > >   /* Functions */
> > > >   {"FindByNick", llua_user_FindByNick},
> > > >
> > > >   /* Methods */
> > > >   {"GetNick", llua_user_GetNick},
> > > >   {NULL, NULL}
> > > > };
> > > >
> > > > /* Metatable */
> > > > static const luaL_reg llua_user_m[] = {
> > > >   {"__tostring", llua_user_tostring},
> > > >   {NULL, NULL}
> > > > };
> > > >
> > > > int lluaopen_user (lua_State *L) {
> > > >   luaL_openlib(L, "user", llua_user_f, 0);
> > > >   luaL_newmetatable(L, TYPE);
> > > >   luaL_openlib(L, 0, llua_user_m, 0); /* mt */
> > > >
> > > >   lua_pushliteral(L, "__index");
> > > >   lua_pushvalue(L, -3);
> > > >   lua_rawset(L, -3);
> > > >
> > > >   lua_pushliteral(L, "__metatable");
> > > >   lua_pushvalue(L, -3);
> > > >   lua_rawset(L, -3);
> > > >
> > > >   lua_pop(L, 1);
> > > >   return 1;
> > > > }
> > > >
> > > > When I use "user:GetNick()" in Lua, I get the error: attempt to index
> > > > field '?' (a nil value).
> > > >
> > > > getmetatable(user) returns nil, tostring(user) returns "user:
> > > > 0x815598c". What exactly am I doing wrong?
> > > >
> > > > Anders
> > >
> > >
>
>
Reply | Threaded
Open this post in threaded view
|

RE: Problem with userdata (metatable)

jdarling
In reply to this post by Anders Bergh-2
> TYPE is defined as "L2.user".

Unless something has changed you can't use dot notation in your libarary
or variable names.

I use __index and __newindex to "catch" object properties __index is
read (or get) and __newindex is write (or set).  Instead they should be
set to the meta-table (as your doing).  My guess (and at this point its
only a guess) is that the dot notation in your table name is throwing
things off.  Try "L2_user" instead of "L2.user" and see what happens.

>
> The GD binding example code works in 5.1 (the methods work), but they
> don't in my code so there must be something I'm doing differently...
> but what? Reading your Delphi code didn't really help me (I don't have
> a C function for __index, and I couldn't exactly figure out what to do
> instead). Should I open the library in a certain way?
>
> Anders


Reply | Threaded
Open this post in threaded view
|

Re: Problem with userdata (metatable)

Anders Bergh-2
Looks like methods work now, but I have another problem. When I use
"user:GetNick()" in Lua, it segfaults.

All I get are pointers to users, and I create the userdata with:

struct user *llua_pushuser (lua_State *L, struct user *user_ptr) {
  struct user *l_user = (struct user*)lua_newuserdata(L, sizeof(struct user*));
  l_user = user_ptr;
  luaL_getmetatable(L, TYPE);
  lua_setmetatable(L, -2);
  return l_user;
}

Now when I use "PrintUserInfo(llua_checkuser(L, 1))" in the GetNick C
function it segfaults:

PrintUserInfo: 0x8158a4c
 -> nick:
 -> numeric: ¸hï·
 -> oper: 96
Segmentation fault

Here's my "llua_checkuser" function:

struct user *llua_checkuser (lua_State *L, int index) {
  struct user *user_ptr;
  luaL_checktype(L, index, LUA_TUSERDATA);
  user_ptr = (struct user*)luaL_checkudata(L, index, TYPE);
  if (user_ptr == NULL) luaL_typerror(L, index, TYPE);
  return user_ptr;
}

I think 0x8158a4c points to something inside Lua, and not the user
pointer... I hope I make sense. Is there anything I'm doing wrong
here?

Anders

On 4/12/06, [hidden email] <[hidden email]> wrote:

> > TYPE is defined as "L2.user".
>
> Unless something has changed you can't use dot notation in your libarary
> or variable names.
>
> I use __index and __newindex to "catch" object properties __index is
> read (or get) and __newindex is write (or set).  Instead they should be
> set to the meta-table (as your doing).  My guess (and at this point its
> only a guess) is that the dot notation in your table name is throwing
> things off.  Try "L2_user" instead of "L2.user" and see what happens.
>
> >
> > The GD binding example code works in 5.1 (the methods work), but they
> > don't in my code so there must be something I'm doing differently...
> > but what? Reading your Delphi code didn't really help me (I don't have
> > a C function for __index, and I couldn't exactly figure out what to do
> > instead). Should I open the library in a certain way?
> >
> > Anders
>
>
>
Reply | Threaded
Open this post in threaded view
|

Re: Problem with userdata (metatable)

Luiz Henrique de Figueiredo
> struct user *llua_pushuser (lua_State *L, struct user *user_ptr) {
>   struct user *l_user = (struct user*)lua_newuserdata(L, sizeof(struct user*));

I think you need this:

 struct user **l_user = (struct user**)lua_newuserdata(L, sizeof(struct user*));
 *l_user = user_ptr;
Reply | Threaded
Open this post in threaded view
|

Re: Problem with userdata (metatable)

Anders Bergh-2
Hmm, I tried this:

struct user *llua_pushuser (lua_State *L, struct user *user_ptr) {
  struct user **l_user = (struct user**)lua_newuserdata(L,
sizeof(struct user*));
  *l_user = user_ptr;
  luaL_getmetatable(L, TYPE);
  lua_setmetatable(L, -2);
  return *l_user; /* is this right? using return l_user made gcc say
warning: return from incompatible pointer type */
}

Output:
PrintUserInfo: 0x8158a4c
 -> nick: ÐØ
 -> numeric: ¸øí·
 -> oper: 96
Segmentation fault

Anders

On 4/12/06, Luiz Henrique de Figueiredo <[hidden email]> wrote:
> > struct user *llua_pushuser (lua_State *L, struct user *user_ptr) {
> >   struct user *l_user = (struct user*)lua_newuserdata(L, sizeof(struct user*));
>
> I think you need this:
>
>  struct user **l_user = (struct user**)lua_newuserdata(L, sizeof(struct user*));
>  *l_user = user_ptr;
>
Reply | Threaded
Open this post in threaded view
|

RE: Problem with userdata (metatable)

jdarling
In reply to this post by Anders Bergh-2
Now we get into where LUA gets confusing to me :).  If you use
newuserdata then you will recieve a blank block of memeory that you
should use for your object.  So if for example you have a TMyClass you
might think that the following would work:

var
  MyInst : TMyClass;
  pData  : Pointer;
begin
  MyInst := TMyClass.Create;
  pData := lua_newuserdata(LuaState, SizeOf(Pointer));
  pData^ := MyInst;
end;

BUT IT WONT!  Instead you would have to do something like this:

var
  MyInst : TMyClass;
  pData  : Pointer;
begin
  MyInst := lua_newuserdata(LuaState, SizeOf(Pointer));
  MyInst.InitInstance(nil);
end;

The reason is that when you use newuserdata you are telling LUA to
allocate your memory for you.  Also if you use it this way then you
have to have an __gc method in your metatable.

What I do instead is push my self pointer onto the LUA table that
represents my object.  Something as such:

function new_<#ClassName#>(L:Plua_State): Integer; cdecl;
var
  c : <#ClassName#>;
begin
  result := nil;
  if lua_type(L, 1) <> LUA_TTABLE then
    lua_remove(L, 1): // Hack to allow TMyClass:new() or TMyClass.new to
work
  c := <#ClassName#>.Create;
  LuaSetTableLightUserData(L, 1, '_Self', c);
  luaL_getmetatable(L, Lua<#ClassName#>ClassName);
  lua_setmetatable(L, -2);
  result := 1;
end;

This in turn sets up a new entery in the object table for each instance
with the value of _Self being the pointer to c.  Then I have a check
method:

function Check<#ClassName#>(L:Plua_State; Idx : Integer): <#ClassName#>;
begin
  result := nil;
  if lua_type(L, Idx) = LUA_TTABLE then
    result := LuaGetTableLightUserData(L, Idx, '_Self')
  else
    lua_typeerror(L, Idx, Lua<#ClassName#>ClassName);
end;

And make use of it as:

function Lua<#ClassName#><#MethodName#>(L: Plua_State):integer; cdecl;
var
  c : <#ClassName#>;
begin
  c := Check(L, 1); // Get the reference
  lua_remove(L, 1); // remove the temporary operating table so operators
are in normal 1..x order
  c.<#MethodName#>([Oper0..OperN]);
  result := MethodResultCount;
end;

Above is kinda psudo code as is everything, the Lua parts are real, the
rest is from my template I use to import objects from Delphi into LUA.
Again take a look at LUNA and the tutorial that was posted here a few
days ago in a post entitled:  Lua api windows tutorial by Jeff Jacob.
They are good references.

 - Jeremy

"Help I suffer from the oxymoron Corporate Security."


> -------- Original Message --------
> Subject: Re: Problem with userdata (metatable)
> From: "Anders Bergh" <[hidden email]>
> Date: Wed, April 12, 2006 1:47 pm
> To: "Lua list" <[hidden email]>
>
> Looks like methods work now, but I have another problem. When I use
> "user:GetNick()" in Lua, it segfaults.
>
> All I get are pointers to users, and I create the userdata with:
>
> struct user *llua_pushuser (lua_State *L, struct user *user_ptr) {
>   struct user *l_user = (struct user*)lua_newuserdata(L, sizeof(struct user*));
>   l_user = user_ptr;
>   luaL_getmetatable(L, TYPE);
>   lua_setmetatable(L, -2);
>   return l_user;
> }
>
> Now when I use "PrintUserInfo(llua_checkuser(L, 1))" in the GetNick C
> function it segfaults:
>
> PrintUserInfo: 0x8158a4c
>  -> nick:
>  -> numeric: ¸hï·
>  -> oper: 96
> Segmentation fault
>
> Here's my "llua_checkuser" function:
>
> struct user *llua_checkuser (lua_State *L, int index) {
>   struct user *user_ptr;
>   luaL_checktype(L, index, LUA_TUSERDATA);
>   user_ptr = (struct user*)luaL_checkudata(L, index, TYPE);
>   if (user_ptr == NULL) luaL_typerror(L, index, TYPE);
>   return user_ptr;
> }
>
> I think 0x8158a4c points to something inside Lua, and not the user
> pointer... I hope I make sense. Is there anything I'm doing wrong
> here?
>
> Anders
>
> On 4/12/06, [hidden email] <[hidden email]> wrote:
> > > TYPE is defined as "L2.user".
> >
> > Unless something has changed you can't use dot notation in your libarary
> > or variable names.
> >
> > I use __index and __newindex to "catch" object properties __index is
> > read (or get) and __newindex is write (or set).  Instead they should be
> > set to the meta-table (as your doing).  My guess (and at this point its
> > only a guess) is that the dot notation in your table name is throwing
> > things off.  Try "L2_user" instead of "L2.user" and see what happens.
> >
> > >
> > > The GD binding example code works in 5.1 (the methods work), but they
> > > don't in my code so there must be something I'm doing differently...
> > > but what? Reading your Delphi code didn't really help me (I don't have
> > > a C function for __index, and I couldn't exactly figure out what to do
> > > instead). Should I open the library in a certain way?
> > >
> > > Anders
> >
> >
> >

Reply | Threaded
Open this post in threaded view
|

Re: Problem with userdata (metatable)

Anders Bergh-2
Awesome, it works now! Thank you for all help!

Here's the working code, if anyone's interested:

int lluaopen_user (lua_State *L) {
  luaL_newmetatable(L, TYPE);

  lua_pushstring(L, "__index");
  lua_pushvalue(L, -2);
  lua_settable(L, -3);

  luaL_openlib(L, NULL, llua_user_m, 0);
  luaL_openlib(L, "user", llua_user_f, 0);
  return 1;
}

static const luaL_reg llua_user_f[] = {
  {"FindByNick", llua_user_FindByNick},
  {NULL, NULL}
};

static const luaL_reg llua_user_m[] = {
  {"__tostring", llua_user_tostring},
  {"GetNick", llua_user_GetNick},
  {NULL, NULL}
};

struct user *llua_checkuser (lua_State *L, int index) {
  struct user *user_ptr;
  luaL_checktype(L, index, LUA_TUSERDATA);
  user_ptr = *(struct user**)luaL_checkudata(L, index, TYPE);
  if (user_ptr == NULL) luaL_typerror(L, index, TYPE);
  return user_ptr;
}

struct user *llua_pushuser (lua_State *L, struct user *user_ptr) {
  struct user **l_user = (struct user**)lua_newuserdata(L,
sizeof(struct user*));
  *l_user = user_ptr;
  luaL_getmetatable(L, TYPE);
  lua_setmetatable(L, -2);
  return l_user;
}

On 4/12/06, [hidden email] <[hidden email]> wrote:

> Now we get into where LUA gets confusing to me :).  If you use
> newuserdata then you will recieve a blank block of memeory that you
> should use for your object.  So if for example you have a TMyClass you
> might think that the following would work:
>
> var
>   MyInst : TMyClass;
>   pData  : Pointer;
> begin
>   MyInst := TMyClass.Create;
>   pData := lua_newuserdata(LuaState, SizeOf(Pointer));
>   pData^ := MyInst;
> end;
>
> BUT IT WONT!  Instead you would have to do something like this:
>
> var
>   MyInst : TMyClass;
>   pData  : Pointer;
> begin
>   MyInst := lua_newuserdata(LuaState, SizeOf(Pointer));
>   MyInst.InitInstance(nil);
> end;
>
> The reason is that when you use newuserdata you are telling LUA to
> allocate your memory for you.  Also if you use it this way then you
> have to have an __gc method in your metatable.
>
> What I do instead is push my self pointer onto the LUA table that
> represents my object.  Something as such:
>
> function new_<#ClassName#>(L:Plua_State): Integer; cdecl;
> var
>   c : <#ClassName#>;
> begin
>   result := nil;
>   if lua_type(L, 1) <> LUA_TTABLE then
>     lua_remove(L, 1): // Hack to allow TMyClass:new() or TMyClass.new to
> work
>   c := <#ClassName#>.Create;
>   LuaSetTableLightUserData(L, 1, '_Self', c);
>   luaL_getmetatable(L, Lua<#ClassName#>ClassName);
>   lua_setmetatable(L, -2);
>   result := 1;
> end;
>
> This in turn sets up a new entery in the object table for each instance
> with the value of _Self being the pointer to c.  Then I have a check
> method:
>
> function Check<#ClassName#>(L:Plua_State; Idx : Integer): <#ClassName#>;
> begin
>   result := nil;
>   if lua_type(L, Idx) = LUA_TTABLE then
>     result := LuaGetTableLightUserData(L, Idx, '_Self')
>   else
>     lua_typeerror(L, Idx, Lua<#ClassName#>ClassName);
> end;
>
> And make use of it as:
>
> function Lua<#ClassName#><#MethodName#>(L: Plua_State):integer; cdecl;
> var
>   c : <#ClassName#>;
> begin
>   c := Check(L, 1); // Get the reference
>   lua_remove(L, 1); // remove the temporary operating table so operators
> are in normal 1..x order
>   c.<#MethodName#>([Oper0..OperN]);
>   result := MethodResultCount;
> end;
>
> Above is kinda psudo code as is everything, the Lua parts are real, the
> rest is from my template I use to import objects from Delphi into LUA.
> Again take a look at LUNA and the tutorial that was posted here a few
> days ago in a post entitled:  Lua api windows tutorial by Jeff Jacob.
> They are good references.
>
>  - Jeremy
>
> "Help I suffer from the oxymoron Corporate Security."
>
>
> > -------- Original Message --------
> > Subject: Re: Problem with userdata (metatable)
> > From: "Anders Bergh" <[hidden email]>
> > Date: Wed, April 12, 2006 1:47 pm
> > To: "Lua list" <[hidden email]>
> >
> > Looks like methods work now, but I have another problem. When I use
> > "user:GetNick()" in Lua, it segfaults.
> >
> > All I get are pointers to users, and I create the userdata with:
> >
> > struct user *llua_pushuser (lua_State *L, struct user *user_ptr) {
> >   struct user *l_user = (struct user*)lua_newuserdata(L, sizeof(struct user*));
> >   l_user = user_ptr;
> >   luaL_getmetatable(L, TYPE);
> >   lua_setmetatable(L, -2);
> >   return l_user;
> > }
> >
> > Now when I use "PrintUserInfo(llua_checkuser(L, 1))" in the GetNick C
> > function it segfaults:
> >
> > PrintUserInfo: 0x8158a4c
> >  -> nick:
> >  -> numeric: ¸hï·
> >  -> oper: 96
> > Segmentation fault
> >
> > Here's my "llua_checkuser" function:
> >
> > struct user *llua_checkuser (lua_State *L, int index) {
> >   struct user *user_ptr;
> >   luaL_checktype(L, index, LUA_TUSERDATA);
> >   user_ptr = (struct user*)luaL_checkudata(L, index, TYPE);
> >   if (user_ptr == NULL) luaL_typerror(L, index, TYPE);
> >   return user_ptr;
> > }
> >
> > I think 0x8158a4c points to something inside Lua, and not the user
> > pointer... I hope I make sense. Is there anything I'm doing wrong
> > here?
> >
> > Anders
> >
> > On 4/12/06, [hidden email] <[hidden email]> wrote:
> > > > TYPE is defined as "L2.user".
> > >
> > > Unless something has changed you can't use dot notation in your libarary
> > > or variable names.
> > >
> > > I use __index and __newindex to "catch" object properties __index is
> > > read (or get) and __newindex is write (or set).  Instead they should be
> > > set to the meta-table (as your doing).  My guess (and at this point its
> > > only a guess) is that the dot notation in your table name is throwing
> > > things off.  Try "L2_user" instead of "L2.user" and see what happens.
> > >
> > > >
> > > > The GD binding example code works in 5.1 (the methods work), but they
> > > > don't in my code so there must be something I'm doing differently...
> > > > but what? Reading your Delphi code didn't really help me (I don't have
> > > > a C function for __index, and I couldn't exactly figure out what to do
> > > > instead). Should I open the library in a certain way?
> > > >
> > > > Anders
> > >
> > >
> > >
>
>