Page 2 of 4 FirstFirst 1234 LastLast
Results 11 to 20 of 36

Thread: using Delphi classes in lua :)

  1. #11

    using Delphi classes in lua :)

    Quote Originally Posted by jdarling
    WOW you mean I'm not the only freak using LUA in Delphi?
    LOL!

    Quote Originally Posted by jdarling
    Nice work thus far, I've been working on a way to create wrappers for units and objects for my own code. I'll have to take a look at what you've put together as it may aid along the way .
    Thanks for the nice comments, and I am just glad to be able to occasionally help other people after myself getting lots of help from the net over the years

    cheers,
    Paul.

  2. #12

    using Delphi classes in lua :)

    Quote Originally Posted by jdarling
    If you write an __newindex handler (writer) that uses RTTI to look at the parent class and write a specialized __index handler (reader) then you can emulate properties quite well. I have this working some place, but the method callers arn't complete yet. Actually the code above gives me some ideas so I may be posting up my code for LUA some time soon too
    I was thinking about '__index' as well, but as far as I can figure this would only help with making readable properties, not writable ones

    How would using '__newindex' help with emulating properties? This is only called if one is adding a new key + value to a table, not for pre-existing keys...

    I would be interested in how you got the '__newindex' working for this sort of thing

    Also I have no clue as to if it is even possible to protect the existing 'class methods' created in the table from being accidently overwritten by a lua script using the table and assigning a value to that key...

    Any thoughts on that one?

    cheers,
    Paul.

  3. #13

    using Delphi classes in lua :)

    I'm not sure if this will help us guys, but I found this post over on a Lua forum:

    http://www.icynorth.com/forums/viewt...404&highlight=

    looks interesting :-)

    cheers,
    Paul

  4. #14

    using Delphi classes in lua :)

    Quote Originally Posted by paul_nicholls
    Quote Originally Posted by jdarling
    If you write an __newindex handler (writer) that uses RTTI to look at the parent class and write a specialized __index handler (reader) then you can emulate properties quite well. I have this working some place, but the method callers arn't complete yet. Actually the code above gives me some ideas so I may be posting up my code for LUA some time soon too
    I was thinking about '__index' as well, but as far as I can figure this would only help with making readable properties, not writable ones

    How would using '__newindex' help with emulating properties? This is only called if one is adding a new key + value to a table, not for pre-existing keys...

    I would be interested in how you got the '__newindex' working for this sort of thing

    Also I have no clue as to if it is even possible to protect the existing 'class methods' created in the table from being accidently overwritten by a lua script using the table and assigning a value to that key...

    Any thoughts on that one?

    cheers,
    Paul.
    Just as soon as I have the code completed and cleaned up I'll post it up for everyone to use. The basic idea is this:

    Create your "Class" using the methods provided in Luna thus hiding the metatable and object level manager from the Lua script in general. Overide the __index and __newindex (witch fires when an unknown is set) and make sure that ALL properties are removed from the meta table. Any time a person makes a request to the object using dot notation either __index (read) or __newindex (write) will be fired, using RTTI scan the object and find out if the property exists, if so then return/set the value otherwise throw an error or pass it back up to Lua as a new table entitity using lua_settable(L, TableIndex) lua_pushstring(L, [PropName]) lua_pushvalue(L, val). Thus the next time its accessed it won't fire __index or __newindex, since you have caught the ones that do fire these "events" (and I use the term loosly) your code will still execute. Now before you ask what if the person overrides __index or __newindex remember that we hid the MetaTable and ObjectTable from the user, they can still get at it using upval() but thats another topic for another day. You simply have to let your users know not to screw with the __index and __newindex methods attached to your objects

  5. #15

    using Delphi classes in lua :)

    Quote Originally Posted by jdarling
    Quote Originally Posted by paul_nicholls
    Quote Originally Posted by jdarling
    If you write an __newindex handler (writer) that uses RTTI to look at the parent class and write a specialized __index handler (reader) then you can emulate properties quite well. I have this working some place, but the method callers arn't complete yet. Actually the code above gives me some ideas so I may be posting up my code for LUA some time soon too
    I was thinking about '__index' as well, but as far as I can figure this would only help with making readable properties, not writable ones

    How would using '__newindex' help with emulating properties? This is only called if one is adding a new key + value to a table, not for pre-existing keys...

    I would be interested in how you got the '__newindex' working for this sort of thing

    Also I have no clue as to if it is even possible to protect the existing 'class methods' created in the table from being accidently overwritten by a lua script using the table and assigning a value to that key...

    Any thoughts on that one?

    cheers,
    Paul.
    Just as soon as I have the code completed and cleaned up I'll post it up for everyone to use. The basic idea is this:

    Create your "Class" using the methods provided in Luna thus hiding the metatable and object level manager from the Lua script in general. Overide the __index and __newindex (witch fires when an unknown is set) and make sure that ALL properties are removed from the meta table. Any time a person makes a request to the object using dot notation either __index (read) or __newindex (write) will be fired, using RTTI scan the object and find out if the property exists, if so then return/set the value otherwise throw an error or pass it back up to Lua as a new table entitity using lua_settable(L, TableIndex) lua_pushstring(L, [PropName]) lua_pushvalue(L, val). Thus the next time its accessed it won't fire __index or __newindex, since you have caught the ones that do fire these "events" (and I use the term loosly) your code will still execute. Now before you ask what if the person overrides __index or __newindex remember that we hid the MetaTable and ObjectTable from the user, they can still get at it using upval() but thats another topic for another day. You simply have to let your users know not to screw with the __index and __newindex methods attached to your objects
    Ahh! that makes sense, with the starting with no properties! cool
    I'll give it a go myself in the meantime to try it

    cheers,
    Paul.

  6. #16

    using Delphi classes in lua :)

    Ok, this is going to be ugly as I haven't posted the TLUA component yet, but I think you can figure it out w/o it as basically all you have to do is replace its reference with a Plua_State

    This code is my reference code for my Delphi->Lua application that is comming around:
    [pascal]unit TestLuaClass;

    interface

    uses
    Classes, LuaWrapper, Lua, LuaUtils, Lauxlib, LuaLib;

    type
    TTestClass=class(TPersistent)
    private
    FBalance: Double;
    procedure SetBalance(const Value: Double);
    public
    class procedure RegisterTo(LuaScript:TLUA);
    published
    procedure Deposit(Amountouble);
    procedure Withdraw(Amountouble);
    property Balance : Double read FBalance write SetBalance;
    end;

    implementation

    uses
    SysUtils,
    TypInfo;

    const
    LuaClassName = 'TestClass';

    function Check(L: Plua_State; Idx : Integer) : TTestClass;
    begin
    result := nil;
    if lua_type(L, Idx) = LUA_TTABLE then
    result := LuaGetTableLightUserData(L, Idx, '_Self')
    else
    luaL_typerror(L, Idx, LuaClassName);
    end;

    function new_TestClass(L: Plua_State): Integer; cdecl;
    var
    c : TTestClass;
    begin
    if lua_type(L, 1) <> LUA_TTABLE then
    lua_remove(L, 1);
    c := TTestClass.Create;
    LuaSetTableLightUserData(L, 1, '_Self', c);
    luaL_getmetatable(L, LuaClassName);
    lua_setmetatable(L, -2);
    result := 1;
    end;

    function gc_TestClass(L: Plua_State): Integer; cdecl;
    var
    c : TTestClass;
    begin
    c := Check(L, 1);
    c.Free;
    result := 0;
    end;

    function indexTestClass(L: Plua_State): Integer; cdecl;
    var
    c : TTestClass;
    propName : String;
    v : Variant;
    begin
    c := Check(L, 1);
    lua_remove(L, 1);
    propName := LuaToString(L, 1);
    if IsPublishedProp(c, propName) then
    begin
    v := GetPropValue(c, propName);
    LuaPushVariant(L, v);
    end
    else
    luaL_error(L, PChar('Property "'+propName+'" does not exist'));
    result := 1;
    end;

    function newindexTestClass(LLua_State): Integer; cdecl;
    var
    c : TTestClass;
    propName : String;
    v : Variant;
    begin
    c := Check(L, 1);
    lua_remove(L, 1);
    propName := LuaToString(L, 1);
    v := LuaToVariant(L, 2);
    if IsPublishedProp(c, propName) then
    SetPropValue(c, propName, v)
    else
    luaL_error(L, PChar('Property "'+propName+'" does not exist'));
    result := 0;
    end;

    function luaDeposit(L: Plua_State): Integer; cdecl;
    var
    c : TTestClass;
    begin
    c := Check(L, 1);
    lua_remove(L, 1);
    if lua_type(L, 1)<>LUA_TNUMBER then
    luaL_error(L, 'Deposit expects one parameter (Amount) that should be an integer.')
    else
    c.Deposit(lua_tonumber(L, 1));
    result := 0;
    end;

    function luaWithdraw(L: Plua_State): Integer; cdecl;
    var
    c : TTestClass;
    begin
    c := Check(L, 1);
    lua_remove(L, 1);
    if lua_type(L, 1)<>LUA_TNUMBER then
    luaL_error(L, 'Withdraw expects one parameter (Amount) that should be an integer.')
    else
    c.Withdraw(lua_tonumber(L, 1));
    result := 0;
    end;

    { TTestClass }

    procedure TTestClass.Deposit(Amount: Double);
    begin
    FBalance := FBalance + Amount;
    end;

    class procedure TTestClass.RegisterTo(LuaScript: TLUA);
    var
    MetaTable,
    MethodTable,
    Methods : Integer;
    begin
    lua_newtable(LuaScript.LuaState);
    Methods := lua_gettop(LuaScript.LuaState);

    luaL_newmetatable(LuaScript.LuaState, LuaClassName);
    MetaTable := lua_gettop(LuaScript.LuaState);

    lua_pushstring(LuaScript.LuaState, LuaClassName);
    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, indexTestClass);
    lua_settable(LuaScript.LuaState, MetaTable);

    lua_pushliteral(LuaScript.LuaState, '__newindex');
    lua_pushcfunction(LuaScript.LuaState, newindexTestClass);
    lua_settable(LuaScript.LuaState, MetaTable);

    lua_pushliteral(LuaScript.LuaState, '__gc');
    lua_pushcfunction(LuaScript.LuaState, gc_TestClass);
    lua_settable(LuaScript.LuaState, MetaTable);

    lua_newtable(LuaScript.LuaState);
    MethodTable := lua_gettop(LuaScript.LuaState);
    lua_pushliteral(LuaScript.LuaState, '__call');
    lua_pushcfunction(LuaScript.LuaState, new_TestClass);
    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);

    //Test Method
    lua_pushstring(LuaScript.LuaState, 'Deposit');
    lua_pushcfunction(LuaScript.LuaState, luaDeposit);
    lua_settable(LuaScript.LuaState, Methods);

    lua_pushstring(LuaScript.LuaState, 'Withdraw');
    lua_pushcfunction(LuaScript.LuaState, luaWithdraw);
    lua_settable(LuaScript.LuaState, Methods);
    //End of Test Method}

    lua_pop(LuaScript.LuaState, 2);
    end;

    procedure TTestClass.SetBalance(const Value: Double);
    begin
    FBalance := Value;
    end;

    procedure TTestClass.Withdraw(Amount: Double);
    begin
    FBalance := FBalance - Amount;
    end;

    end.[/pascal]

  7. #17

    using Delphi classes in lua :)

    Awsome work chief!

    That TTestClass.RegisterTo() method is almost scary! hehe

    Paul.

  8. #18

    using Delphi classes in lua :)

    Actually, I was thinking. Instead of subclassing from TPersistent, you could possible do something like so instead for more flexability with base class types:

    Code:
    &#123;$M+&#125;
      TTestClass=class 
      private 
        FBalance&#58; Double; 
        procedure SetBalance&#40;const Value&#58; Double&#41;; 
      public 
        class procedure RegisterTo&#40;LuaScript&#58;TLUA&#41;; 
      published 
        procedure Deposit&#40;Amount&#58;Double&#41;; 
        procedure Withdraw&#40;Amount&#58;Double&#41;; 
        property  Balance &#58; Double read FBalance write SetBalance; 
      end;
    &#123;$M-&#125;

    I believe the ($M+} will also give you RTTI info as well

    Paul.

  9. #19

    using Delphi classes in lua :)

    Quote Originally Posted by paul_nicholls
    Actually, I was thinking. Instead of subclassing from TPersistent, you could possible do something like so instead for more flexability with base class types:

    Code:
    &#123;$M+&#125;
      TTestClass=class 
      private 
        FBalance&#58; Double; 
        procedure SetBalance&#40;const Value&#58; Double&#41;; 
      public 
        class procedure RegisterTo&#40;LuaScript&#58;TLUA&#41;; 
      published 
        procedure Deposit&#40;Amount&#58;Double&#41;; 
        procedure Withdraw&#40;Amount&#58;Double&#41;; 
        property  Balance &#58; Double read FBalance write SetBalance; 
      end;
    &#123;$M-&#125;

    I believe the ($M+} will also give you RTTI info as well

    Paul.
    Well actually when complete the importer will just be ran on your source and will create a wrapper unit for it. The problem was I needed an object that was quick and easy to test on that exhibited everything I wanted to wrap up. The only one I haven't figured out yet is properties with array indexes. BTW: If you want to use object assignment for properties then you have to do a GetPropType(Instance, PropName) = tkClass (thats off the top of my head so its probiably wrong) and then get the table's reference to _Self. Other then that its pretty straight forward . Hopefully I get everything completed some time soon.

  10. #20

    using Delphi classes in lua :)

    For you info, using jdarling's idea of an empty table + __index and __newindex I have updated my TLuaClass to check/protect methods + properties

    example:

    class declaration

    Code:
        TLuaClassCounter = Class&#40;TLuaClass&#41;
        Private
            FCount&#58; Integer;
    
            Function IncCount&#40;L&#58; lua_State&#41;&#58; Integer;
            Function GetCount&#40;L&#58; lua_State&#41;&#58; Integer;
        Protected
            Function  CallLuaMethod&#40;L&#58; lua_State; MethodIndex&#58; Integer&#41;&#58; Integer; Override;
            Procedure ReadPropertyValue&#40;L&#58; lua_State; PropertyIndex&#58; Integer&#41;; Override;
            Procedure WritePropertyValue&#40;L&#58; lua_State; PropertyIndex&#58; Integer&#41;; Override;
        Public
            Constructor Create; Override;
        End;
    class body
    Code:
    Constructor TLuaClassCounter.Create;
    Begin
        Inherited Create;
    
        RegisterLuaMethod  &#40;'IncCount',0&#41;;
        RegisterLuaMethod  &#40;'GetCount',1&#41;;
        RegisterLuaProperty&#40;'Count'   ,0,eIntegerProperty,False&#41;;
        RegisterLuaProperty&#40;'Count2x' ,1,eIntegerProperty,True&#41;;
        RegisterLuaProperty&#40;'Self'    ,2,eLuaClassProperty,True&#41;;
    
        FCount &#58;= 0;
    End;
    &#123;.......................................................&#125;
    
    &#123;.......................................................&#125;
    Function  TLuaClassCounter.IncCount&#40;L&#58; lua_State&#41;&#58; Integer;
    Begin
        Inc&#40;FCount&#41;;
    
        Result &#58;= 0;
    End;
    &#123;.......................................................&#125;
    
    &#123;.......................................................&#125;
    Function  TLuaClassCounter.GetCount&#40;L&#58; lua_State&#41;&#58; Integer; 
    Begin
        lua_pushnumber&#40;L,FCount&#41;;
    
        Result &#58;= 1;
    End;
    &#123;.......................................................&#125;
    
    &#123;.......................................................&#125;
    Function  TLuaClassCounter.CallLuaMethod&#40;L&#58; lua_State; MethodIndex&#58; Integer&#41;&#58; Integer;
    Begin
        Result &#58;= 0;
    
        Case MethodIndex Of
            0 &#58; Result &#58;= IncCount&#40;L&#41;;
            1 &#58; Result &#58;= GetCount&#40;L&#41;;
        Else
        End;
    End;
    &#123;.......................................................&#125;
    
    &#123;.......................................................&#125;
    Procedure TLuaClassCounter.ReadPropertyValue&#40;L&#58; lua_State; PropertyIndex&#58; Integer&#41;;
    Begin
        Case PropertyIndex Of
            0 &#58; lua_pushnumber&#40;L,FCount&#41;;
            1 &#58; lua_pushnumber&#40;L,FCount * 2&#41;;
            2 &#58; PushOntoLuaStack&#40;L&#41;;
        Else
        End;
    
        Result &#58;= 1;
    End;
    &#123;.......................................................&#125;
    
    &#123;.......................................................&#125;
    Procedure TLuaClassCounter.WritePropertyValue&#40;L&#58; lua_State; PropertyIndex&#58; Integer&#41;;
    Var
        Value&#58; Double;
    Begin
        Case PropertyIndex Of
            0 &#58; FCount &#58;= Trunc&#40;lua_tonumber&#40;L,3&#41;&#41;;
        Else
        End;
    End;
    &#123;.......................................................&#125;
    
    &#123;.......................................................&#125;
    Behind the scenes, no properties or methods can be overwritten in a Lua script, and read-only properties can't be written to in Lua script
    Also, you can't assign the wrong type to writable properties and it will tell you

    BTW, is there anywhere on this site that one can post largeish code/units to share with people?

    cheers,
    Paul

Page 2 of 4 FirstFirst 1234 LastLast

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •