-
Вчера занялся внедрением скриптового движка в продукт. Остановился на 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
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.
-
> CallResultDoudble
ненравится мне этот тип :)
-
LoadFromStream/SaveToStream где?
-
> [1] Palladin © (11.12.08 09:01)
мда уж... опечатался. :))
> [2] wicked © (11.12.08 12:10)
а зачем? Из текстовой строки грузит. а как эту строки доставали - ваше дело. Меньше привязки к юнитам.
-
> Меньше привязки к юнитам.
тогда уж убери Dialogs и ShowMessage а вместо ShowMessage('error running function '+ProcName+': '+lua_tostring(FLUAState, -1)); вызывай событие if Assigned(FOnError) then FOnError('error running function '+ProcName+': '+lua_tostring(FLUAState, -1));
-
> @!!ex © (11.12.08 13:50) [3]
Ну, поток - это более высокий уровень абстракции, чем строка. Реюзабельность класса от этого повысится.
-
А как поначалу LUA оскоблял. Теперь заценил вот :-)
> Реюзабельность класса от этого повысится.
Тогда уже сразу абстракный Stream вешать, можно и с нета и из архива напрямую качать.
-
> tesseract © (11.12.08 15:25) [6]
Конечно абстрактный!
-
TStream и имелся в виду на что-либо выше по иерархии завязываться нет смысла
-
> [4] clickmaker © (11.12.08 13:56)
Спасибо.
> [5] Alkid (11.12.08 14:50)
В данном случае код из моего проекта, котоырй сейчас делаю. А в нем Стримы вообще не используются...
> [6] tesseract © (11.12.08 15:25)
Не ругал я Lua никогда! :) В студию мои ругательства в сторону Lua! говорил, что не имеет смысла использовать в своих проектах, потому что использование чужого кода не учит писать свой.
-
> > @!!ex © (10.12.08 17:56)
Ты ж вроде на С++ перешёл?
-
> [10] Городской Шаман (12.12.08 00:24)
Есть на С++ проекты. Но это не отменило Дельфи проектов. :)
-
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;
За такое перераспределение памяти уволить без выходного пособия.
-
> [12] VMcL © (12.12.08 11:43)
Ваши предложения?
-
Насколько я вижу, добавление элементов в C++ vector через push_back также дефрагментирует память. Разве есть другие варианты? List чтоли делать? Или выделять сразу блоками? Эти способы тоже не панацея.
-
TStringList
-
> 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
-
> [15] Palladin © (12.12.08 12:34)
Еще один "левый" класс. Ради чего? И разве он также не делает realloc?
-
> Dec(Len, 2);
Dec(Len), конечно же )
-
> [16] clickmaker © (12.12.08 12:35)
Я так и делаю, в местах где данные меняются часто и критично по скорости. Здесь скорость не критична, и данные меняются только один раз при инициализации.
|