Конференция "Прочее" » Оценил простоту и мощь Lua
 
  • @!!ex © (10.12.08 17:56) [0]
    Вчера занялся внедрением скриптового движка в продукт.
    Остановился на Lua, как мощном и гибком движке.

    Сделал классовую обертку(может кому понадобится?). Покажите на ошибки, где накосячил?

    unit uLua;

    interface
    uses lua, lualib, lauxlib,
        Dialogs;

    type
     TLUAExternMethod = record
       Name:string;
       Address:lua_CFunction;
     end;

     TLUAParser = class
     protected
       FLUAState:Pointer;
       FExternMethods:array of TLUAExternMethod;
       Procedure   LuaInit;
       Procedure   LuaClose;
       Procedure   LuaUpdateMethods;
       Procedure   LuaAddMethod(const MethodName:string; Method:lua_CFunction);
     public
       Constructor Create();
       Destructor  Destroy(); override;
       Procedure   Clear();
       Procedure   LoadFromMemory(const Text:string);
       Function    Call(const ProcName:string; Params:array of const):boolean;
       Function    CallResultInt(const ProcName:string; Params:array of const):integer;
       Function    CallResultDoudble(const ProcName:string; Params:array of const):double;
       Function    CallResultString(const ProcName:string; Params:array of const):string;
       Procedure   AddMethod(const MethodName:string; Method:lua_CFunction);
     end;

    implementation

    { TLUAParser }

    procedure TLUAParser.AddMethod(const MethodName: string; Method: lua_CFunction);
    begin
     SetLength(FExternMethods,Length(FExternMethods)+1);
     FExternMethods[Length(FExternMethods)-1].Name:=MethodName;
     FExternMethods[Length(FExternMethods)-1].Address:=Method;
     LuaAddMethod(MethodName,Method);
    end;

    Function TLUAParser.Call(const ProcName: string; Params: array of const):boolean;
    var
     i:integer;
    begin
     Result:=true;
     lua_getglobal(FLUAState, PChar(ProcName));
     for i := 0 to Length(Params) - 1 do begin
       case Params[i].VType of
         vtExtended:lua_pushnumber(FLUAState, Params[i].vExtended^);
         vtInteger:lua_pushnumber(FLUAState, Params[i].VInteger);
         vtString:lua_pushstring(FLUAState, PChar(Params[i].VString));
         vtPointer:lua_pushnumber(FLUAState, Params[i].VInteger);
       end;
     end;
     if (lua_pcall(FLUAState, Length(Params), 0, 0) <> 0) then begin
       ShowMessage('error running function '+ProcName+': '+lua_tostring(FLUAState, -1));
       lua_pop(FLUAState, 1);
       Result:=false;
     end;
    end;

    function TLUAParser.CallResultDoudble(const ProcName: string;
     Params: array of const): double;
    begin
     if Call(ProcName,Params) then begin
       Result:=lua_tonumber(FLUAState,-1);
       lua_pop(FLUAState, 1);
     end;
    end;

    function TLUAParser.CallResultInt(const ProcName: string;
     Params: array of const): integer;
    begin
     if Call(ProcName,Params) then begin
       Result:=Round(lua_tonumber(FLUAState,-1));
       lua_pop(FLUAState, 1);
     end;
    end;

    function TLUAParser.CallResultString(const ProcName: string;
     Params: array of const): string;
    begin
     if Call(ProcName,Params) then begin
       Result:=lua_tostring(FLUAState,-1);
       lua_pop(FLUAState, 1);
     end;
    end;

    procedure TLUAParser.Clear;
    begin
     LuaClose();
     LuaInit();
     LuaUpdateMethods;
    end;

    constructor TLUAParser.Create;
    begin
     LuaInit();
    end;

    destructor TLUAParser.Destroy;
    begin
     LuaClose();
     inherited;
    end;

    procedure TLUAParser.LoadFromMemory(const Text: string);
    var
     error:integer;
    begin
     error:=luaL_loadbuffer(FLUAState, PChar(Text), length(Text), 'Chunk');
     if error=0 then
       error:=lua_pcall(FLUAState, 0, 0, 0);
     if (error<>0) then begin
       ShowMessage(lua_tostring(FLUAState, -1));
       lua_pop(FLUAState, 1);
     end
    end;

    procedure TLUAParser.LuaAddMethod(const MethodName: string;
     Method: lua_CFunction);
    begin
     lua_pushcfunction(FLUAState, Method);
     lua_setglobal(FLUAState, PChar(MethodName));
    end;

    procedure TLUAParser.LuaClose;
    begin
     lua_close(FLUAState);
    end;

    procedure TLUAParser.LuaInit;
    begin
     FLUAState:=lua_open();
     luaopen_base(FLUAState);
     luaopen_table(FLUAState);
     luaopen_string(FLUAState);
     luaopen_math(FLUAState);
    end;

    procedure TLUAParser.LuaUpdateMethods;
    var
     i:integer;
    begin
     for I := 0 to Length(FExternMethods) - 1 do
       LuaAddMethod(FExternMethods[i].Name,FExternMethods[i].Address);
    end;

    end.

  • Palladin © (11.12.08 09:01) [1]

    > CallResultDoudble

    ненравится мне этот тип :)
  • wicked © (11.12.08 12:10) [2]
    LoadFromStream/SaveToStream где?
  • @!!ex © (11.12.08 13:50) [3]
    > [1] Palladin ©   (11.12.08 09:01)

    мда уж... опечатался. :))


    > [2] wicked ©   (11.12.08 12:10)

    а зачем?
    Из текстовой строки грузит. а как эту строки доставали - ваше дело.
    Меньше привязки к юнитам.
  • clickmaker © (11.12.08 13:56) [4]
    > Меньше привязки к юнитам.

    тогда уж убери Dialogs и ShowMessage
    а вместо
    ShowMessage('error running function '+ProcName+': '+lua_tostring(FLUAState, -1));
    вызывай событие
    if Assigned(FOnError) then
     FOnError('error running function '+ProcName+': '+lua_tostring(FLUAState, -1));
  • Alkid (11.12.08 14:50) [5]

    > @!!ex ©   (11.12.08 13:50) [3]

    Ну, поток - это более высокий уровень абстракции, чем строка.
    Реюзабельность класса от этого повысится.
  • tesseract © (11.12.08 15:25) [6]
    А как поначалу LUA оскоблял. Теперь заценил вот :-)


    > Реюзабельность класса от этого повысится.


    Тогда уже сразу абстракный  Stream вешать, можно и с нета и из архива напрямую качать.
  • Alkid (11.12.08 18:04) [7]

    > tesseract ©   (11.12.08 15:25) [6]

    Конечно абстрактный!
  • wicked © (11.12.08 18:07) [8]
    TStream и имелся в виду
    на что-либо выше по иерархии завязываться нет смысла
  • @!!ex © (11.12.08 21:32) [9]
    > [4] clickmaker ©   (11.12.08 13:56)

    Спасибо.


    > [5] Alkid   (11.12.08 14:50)

    В данном случае код из моего проекта, котоырй сейчас делаю. А в нем Стримы вообще не используются...

    > [6] tesseract ©   (11.12.08 15:25)

    Не ругал я Lua никогда! :)
    В студию мои ругательства в сторону Lua!
    говорил, что не имеет смысла использовать в своих проектах, потому что использование чужого кода не учит писать свой.
  • Городской Шаман (12.12.08 00:24) [10]

    >
    > @!!ex ©   (10.12.08 17:56)


    Ты ж вроде на С++ перешёл?
  • @!!ex © (12.12.08 09:41) [11]
    > [10] Городской Шаман   (12.12.08 00:24)

    Есть на С++ проекты. Но это не отменило Дельфи проектов. :)
  • VMcL © (12.12.08 11:43) [12]
    procedure TLUAParser.AddMethod(const MethodName: string; Method: lua_CFunction);
    begin
    SetLength(FExternMethods,Length(FExternMethods)+1);
    FExternMethods[Length(FExternMethods)-1].Name:=MethodName;
    FExternMethods[Length(FExternMethods)-1].Address:=Method;
    LuaAddMethod(MethodName,Method);
    end;


    За такое перераспределение памяти уволить без выходного пособия.
  • @!!ex © (12.12.08 12:30) [13]
    > [12] VMcL ©   (12.12.08 11:43)

    Ваши предложения?
  • @!!ex © (12.12.08 12:33) [14]
    Насколько я вижу, добавление элементов в C++ vector через push_back также дефрагментирует память. Разве есть другие варианты?
    List чтоли делать? Или выделять сразу блоками? Эти способы тоже не панацея.
  • Palladin © (12.12.08 12:34) [15]
    TStringList
  • clickmaker © (12.12.08 12:35) [16]
    > SetLength(FExternMethods,Length(FExternMethods)+1);
    > FExternMethods[Length(FExternMethods)-1].Name:=MethodName;
    >
    > FExternMethods[Length(FExternMethods)-1].Address:=Method;

    Len := Length(FExternMethods) + 1;
    SetLength(FExternMethods,Len);
    Dec(Len, 2);
    FExternMethods[Len].Name:=MethodName;
    FExternMethods[Len].Address:=Method;

    на самом деле, можно не каждый раз увеличивать массив на 1, а сразу задать некую длину, и если при добавлении она превышена, перераспределить заново на некую дельту. По аналогии с Capacity в TList
  • @!!ex © (12.12.08 12:35) [17]
    > [15] Palladin ©   (12.12.08 12:34)

    Еще один "левый" класс. Ради чего?
    И разве он также не делает realloc?
  • clickmaker © (12.12.08 12:36) [18]
    > Dec(Len, 2);

    Dec(Len), конечно же )
  • @!!ex © (12.12.08 12:37) [19]
    > [16] clickmaker ©   (12.12.08 12:35)

    Я так и делаю, в местах где данные меняются часто и критично по скорости.
    Здесь скорость не критична, и данные меняются только один раз при инициализации.
 
Конференция "Прочее" » Оценил простоту и мощь Lua
Есть новые Нет новых   [134449   +17][b:0][p:0.003]