lua-users home
lua-l archive

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


Hi,

I think the problem is here:

      if Assigned(m.Code) then
        result := TLuaObjectMethod(m)(l)
      else
        result := 0;


You are calling the method in the instIndex function, returning it's result. Lua expects you to return that function instead.

Suppose you have a class TFoo and a method bar(). When you instantiate a Lua userdata for the TFoo class, and write something like this:

-- I don't know how your constructors looks like...
local foo = TFoo.Create()
foo:bar()

foo's __index metamethod should return a function to be executed by the Lua VM and not on the "C side" (Delphi side ;).

Basically you would have to replace those lines with:

if Assigned(m.Code) then
begin
  lua_pushcfunction(TLuaObjectMethod(m));
  Result:= 1;
end
else
  Result := 0;

But a problem arises here, because a method is different from a Lua C Function. A method is a function that requires an implicit "Self" reference as the first argument and n other arguments as the function/procedure parameters, while a Lua C Function is a function that accepts only a pointer to a lua_State structure (record) and returns an integer (also, it has to be cdecl'ed). I think the best solution would be to create a generic LuaCFunction which would have as it's first two upvalues the parts of a TMethod record:

function dummycclosure(L: PLuaState): integer; cdecl;
var
  m: TMethod;
begin
  m.Data:= lua_touserdata(L, lua_upvalueindex(1));
  m.Code:= lua_touserdata(L, lua_upvalueindex(2));
  Result:= TLuaObjectMethod(m)(L);
end;

And your instIndex would be:

if Assigned(m.Code) then
begin
  lua_pushlightuserdata(L, m.Data);
  lua_pushlightuserdata(L, m.Code);
  lua_pushcclosure(dummycclosure, 2);
  Result:= 1;
end
else
  Result := 0;

This solution should work fine, but it creates a C closure each time it is called.

There are other solutions for you problem, as creating binding functions for your class methods and then putting them into a table, perhaps replacing the __index function with that table, and settings it's __index metamethod for that __index function (confusing?).

I have tried to create a binding mechanism sometime ago but I had to abandon it (cost x benefit). Most of the time, it is easier to create the binding functions manually than to create a run-time system[1] generic enough to accommodate both Delphi's and Lua's particularities. I wish you to be more lucky than me :)

--rb

1. I tried to implement a run-time system to take advantage of Delphi's RTTI. I think that an offline engine would be a bit simpler to implement.

ps: I have not tested any of the code I wrote.