12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421 |
- //******************************************************************************
- //*** LUA SCRIPT FUNCTIONS ***
- //*** ***
- //*** (c) Massimo Magnano 2006 ***
- //*** ***
- //*** ***
- //******************************************************************************
- // File : Lua_Object.pas (rev. 1.0)
- //
- // Description : Access from Lua scripts to TObject Classes
- // (at this time only Properties and methods)
- //
- //******************************************************************************
- // Exported functions :
- //
- // CreateObject(string className, bool CanFree [, param1, ..paramN]) return a new TObject.
- // GetObject(string Name) return an existing TObject.
- //
- // TObject.PropertyName return Property Value as Variant.
- // TObject.PropertyName = (variant Value) set Property Value.
- // TObject:<method name>([param1, .., paramN]) call <method name>, return Result as Variant.
- // TObject:Free() free the object, return True on success.
- // TO-DO :
- // funzioni lua da esportare :
- // enumval(Type :???, value :string) enumstr(Type :???, value :Integer???)
- // nei metodi dove c'è var, come lo torno in Lua?
- // Eventi degli oggetti (una classe per ogni evento + lista con il nome della funzione lua)
- // Gestione delle property di Tipo Record Vedi cos'è PFieldTable
- // + Metodo x avere le property publiche??? invece di usare SetElement
- // * gestione del garbage collector (metafunction _gc)
- // * Gestione di TComponent.<componentname> come se fosse una property tkClass
- // ++ Migliorare la gestione delle property che sono degli array (se possibile???)
- // * Migliorare la registrazione delle classi, andare sempre alla ricerca dell' ancestor
- // COMMENTARE IL CODICE MENTRO ME LO RICORDO
- unit Lua_Object;
- {$J+}
- interface
- uses TypInfo, SysUtils, ScriptableObject, Lua, LuaUtils, lauxlib, Variants;
- type
- {$METHODINFO ON}
- TLuaObject = class(TObject)
- protected
- rInstanceObj :TObject;
- Owned :Boolean;
- class function GetPublicPropertyAccessClass :TClass; virtual; abstract;
- public
- constructor Create(AInstanceObj :TObject; AOwned :Boolean);
- destructor Destroy; override;
- function CallMethod(MethodName :String; const Args : array of variant;
- NeedResult: Boolean): Variant;
- //WARNING : if you want parameters when creating an Object you must write
- // a function with the following form that create the object.
- // You must change every parameter or result of type TClass, TObject
- // with type integer (ObjComAuto do not support this types?????)
- //
- function LuaCreate(ObjClass :Integer) :Integer; overload;
- function GetDefaultArrayProp :String; virtual; abstract;
- function GetArrayPropType(Name :String; index :Variant) :PTypeInfo; virtual; abstract;
- function GetArrayProp(Name :String; index :Variant) :Variant; virtual; abstract;
- procedure SetArrayProp(Name :String; index :Variant; Value :Variant); virtual; abstract;
- //If the ElementType is tkSet or tkEnumeration (except the boolean) you may return the Value
- // in GetElement as a String
- function GetElementType(Name :String) :PTypeInfo; virtual; abstract;
- function GetElement(Name :String) :Variant; virtual; abstract;
- procedure SetElement(Name :String; Value :Variant); virtual; abstract;
- function GetPublicPropInfo(Name :String) :PPropInfo;
- function GetPublicPropValue(Name :String; AsString :Boolean) :Variant;
- procedure SetPublicPropValue(Name :String; Value :Variant);
- property InstanceObj :TObject read rInstanceObj;
- end;
- {$METHODINFO OFF}
- TLuaObjectClass = class of TLuaObject;
- const
- TypeInfoArray : TTypeInfo = (Kind : tkArray; Name :'');
- TypeInfoClass : TTypeInfo = (Kind : tkClass; Name :'');
- procedure RegisterFunctions(L: Plua_State);
- procedure RegisterClass(ObjClass :TClass; LuaClass :TLuaObjectClass=nil);
- procedure RegisterObject(Obj :TObject; Name :String; LuaClass :TLuaObjectClass=nil);
- function SetToString(TypeInfo: PTypeInfo; Value: Integer; Brackets: Boolean): string;
- function StringToSet(EnumInfo: PTypeInfo; const Value: string): Integer;
- implementation
- uses MGList, Classes, Controls;
- const
- OBJHANDLE_STR ='Lua_TObjectHandle';
- ARRAYPROP_STR ='Lua_TObjectArrayProp';
- ARRAYPROPNAME_STR ='Lua_TObjectArrayPropName';
- SETPROP_VALUE ='Lua_TObjectSetPropvalue';
- SETPROP_INFO ='Lua_TObjectSetPropINFO';
- type
- //Record stored in lua stack to mantain TLuaObject
- TLuaObjectData = packed record
- ID : String[20];
- Obj :TLuaObject;
- end;
- PLuaObjectData =^TLuaObjectData;
- TLuaArrayPropData = record
- ID : String[20];
- Obj :TLuaObject;
- PropName :string;
- end;
- TLuaSetPropData = record
- ID :String[20];
- Info :PTypeInfo;
- Value :string;
- end;
- PLuaSetPropData = ^TLuaSetPropData;
- //This List associate an Object Class with a LuaObject Class
- TLuaClassesListData = record
- ObjClass :TClass;
- LuaClass :TLuaObjectClass;
- end;
- PLuaClassesListData =^TLuaClassesListData;
- TLuaClassesList = class(TMGList)
- protected
- InternalData :TLuaClassesListData;
- function allocData :Pointer; override;
- procedure deallocData(pData :Pointer); override;
- function internalFind(ObjClassName :String) :PLuaClassesListData; overload;
- function internalFind(ObjClass :TClass) :PLuaClassesListData; overload;
- public
- function Add(ObjClass :TClass; LuaClass :TLuaObjectClass=nil) :PLuaClassesListData; overload;
- function FindAncestor(ObjClass :TClass) :TLuaObjectClass;
- function Find(ObjClassName :String) :PLuaClassesListData; overload;
- function Find(ObjClass :TClass) :PLuaClassesListData; overload;
- end;
- //This List associate an Existing Object Instance with a Name in the Lua script
- TLuaExistingObjListData = record
- Obj :TObject;
- Name :String;
- end;
- PLuaExistingObjListData =^TLuaExistingObjListData;
- TLuaExistingObjList = class(TMGList)
- protected
- function allocData :Pointer; override;
- procedure deallocData(pData :Pointer); override;
- public
- function Add(Obj :TObject; Name :String) :PLuaExistingObjListData; overload;
- function Find(Name :String) :PLuaExistingObjListData; overload;
- end;
- Var
- LuaClassesList :TLuaClassesList =nil;
- LuaExistingObjList :TLuaExistingObjList =nil;
- procedure MySetPropValue(Instance: TObject; PropInfo: PPropInfo;
- const Value: Variant);
- begin
- //SetPropValue raise an exception when i try to set a class property...
- // even if it's value is a simple Integer (infact GetPropValue return it as Integer)
- if PropInfo^.PropType^.Kind = tkClass
- then SetOrdProp(Instance, PropInfo, Value)
- else SetPropValue(Instance, PropInfo, Value);
- end;
- constructor TLuaObject.Create(AInstanceObj :TObject; AOwned :Boolean);
- begin
- inherited Create;
- rInstanceObj :=AInstanceObj;
- Owned :=AOwned;
- end;
- destructor TLuaObject.Destroy;
- begin
- if Owned then rInstanceObj.Free;
- inherited Destroy;
- end;
- function TLuaObject.LuaCreate(ObjClass :Integer) :Integer;
- begin
- Result :=Integer(TClass(ObjClass).Create);
- end;
- function TLuaObject.CallMethod(MethodName :String; const Args : array of variant;
- NeedResult: Boolean): Variant;
- Var
- scripter :TScriptableObject;
- pRes :PVariant;
- begin
- Result :=NULL;
- scripter :=nil;
- try
- //Try with My Methods
- scripter :=TScriptableObject.Create(Self, false);
- pRes :=scripter.CallMethod(scripter.NameToDispID(MethodName), Args, NeedResult);
- if (pRes<>nil)
- then Result :=pRes^;
- scripter.Free;
- except
- scripter.Free;
- Result :=NULL;
- try
- //Try with InstanceObj Methods
- scripter :=TScriptableObject.Create(rInstanceObj, false);
- pRes :=scripter.CallMethod(scripter.NameToDispID(MethodName), Args, NeedResult);
- if (pRes<>nil)
- then Result :=pRes^;
- scripter.Free;
- except
- scripter.Free;
- Result :=NULL;
- end;
- end;
- end;
- function TLuaObject.GetPublicPropInfo(Name :String) :PPropInfo;
- Var
- _parent :TLuaObjectClass;
- begin
- _parent :=TLuaObjectClass(Self.ClassType);
- repeat
- Result :=GetPropInfo(_parent.GetPublicPropertyAccessClass, Name, tkProperties);
- if (Result=nil)
- then _parent := TLuaObjectClass(_parent.ClassParent);
- //IF the Property is not public in this Class, try in ancestors.
- // This method avoid to redeclare property as published in every TXXXAccess class,
- // for example :
- // TLuaControl <- TLuaWinControl
- // TControl <- TWinControl
- // Without this method, in TLuaWinControl, you might declare every public property
- // of TWinControl including every public property of TControl.
- // With this method, in TLuaWinControl, you can declare only public property of TWinControl
- until (_parent=TLuaObject) or (Result<>nil);
- end;
- (*
- begin
- Result :=GetPropInfo(GetPublicPropertyAccessClass, Name, tkProperties);
- end;
- *)
- function TLuaObject.GetPublicPropValue(Name :String; AsString :Boolean) :Variant;
- Var
- PropInfo :PPropInfo;
- begin
- PropInfo :=GetPublicPropInfo(Name);
- if (PropInfo<>nil)
- then Result :=GetPropValue(rInstanceObj, PropInfo, AsString);
- end;
- procedure TLuaObject.SetPublicPropValue(Name :String; Value :Variant);
- Var
- PropInfo :PPropInfo;
- begin
- PropInfo :=GetPublicPropInfo(Name);
- if (PropInfo<>nil)
- then MySetPropValue(rInstanceObj, PropInfo, Value);
- end;
- //==============================================================================
- //
- function TLuaClassesList.allocData :Pointer;
- begin
- GetMem(Result, sizeof(TLuaClassesListData));
- fillchar(Result^, sizeof(TLuaClassesListData), 0);
- end;
- procedure TLuaClassesList.deallocData(pData :Pointer);
- begin
- FreeMem(pData, sizeof(TLuaClassesListData));
- end;
- function TLuaClassesList.Add(ObjClass :TClass; LuaClass :TLuaObjectClass=nil) :PLuaClassesListData;
- begin
- Result :=Find(ObjClass.ClassName);
- if (Result=nil)
- then Result :=Self.Add;
- if (Result<>nil)
- then begin
- Result^.ObjClass :=ObjClass;
- (*if (LuaClass=nil)
- then Result^.LuaClass :=TLuaObject
- else*) Result^.LuaClass :=LuaClass;
- end;
- end;
- function TLuaClassesList.FindAncestor(ObjClass :TClass) :TLuaObjectClass;
- Var
- _parent :TClass;
- Data :PLuaClassesListData;
- begin
- _parent :=ObjClass.ClassParent;
- Data :=nil;
- while (_parent<>nil) and (Data=nil) do
- begin
- Data :=internalFind(_parent);
- if (Data<>nil)
- then Result :=Data^.LuaClass
- else _parent := _parent.ClassParent;
- end;
- if (Data=nil)
- then Result :=TLuaObject;
- end;
- function TLuaClassesList.internalFind(ObjClassName :String) :PLuaClassesListData;
- function CompByClassName(Tag :Integer; ptData1, ptData2 :Pointer) :Boolean;
- begin
- Result := String(PChar(ptData1)) = Uppercase(PLuaClassesListData(ptData2)^.ObjClass.Classname);
- end;
- begin
- Result :=Self.ExtFind(PChar(Uppercase(ObjClassName)), 0, @CompByClassName);
- end;
- function TLuaClassesList.internalFind(ObjClass :TClass) :PLuaClassesListData;
- function CompByClass(Tag :Integer; ptData1, ptData2 :Pointer) :Boolean;
- begin
- Result := TClass(ptData1) = PLuaClassesListData(ptData2)^.ObjClass;
- end;
- begin
- Result :=Self.ExtFind(ObjClass, 0, @CompByClass);
- end;
- function TLuaClassesList.Find(ObjClass :TClass) :PLuaClassesListData;
- begin
- Result :=Self.internalFind(ObjClass);
- if (Result<>nil)
- then begin
- if (Result^.LuaClass=nil) //The Class is registered, but have no LuaClass,
- //try to find a registered ancestor class
- then Result^.LuaClass :=FindAncestor(Result^.ObjClass);
- end
- else begin
- //The Class is not registered, try to find a registered ancestor class
- InternalData.ObjClass :=ObjClass;
- InternalData.LuaClass :=FindAncestor(ObjClass);
- if (InternalData.LuaClass<>nil)
- then Result :=@InternalData
- else Result :=nil;
- end;
- end;
- function TLuaClassesList.Find(ObjClassName :String) :PLuaClassesListData;
- begin
- Result :=Self.internalFind(ObjClassName);
- if (Result<>nil)
- then begin
- if (Result^.LuaClass=nil) //The Class is registered, but have no LuaClass,
- //try to find a registered ancestor class
- then Result^.LuaClass :=FindAncestor(Result^.ObjClass);
- end
- else begin
- Result :=Self.internalFind(FindClass(ObjClassName));
- if (Result<>nil)
- then begin
- if (Result^.LuaClass=nil) //The Class is registered in VCL, but have no LuaClass,
- //try to find a registered ancestor class
- then Result^.LuaClass :=FindAncestor(Result^.ObjClass);
- end
- end;
- end;
- //==============================================================================
- //
- function TLuaExistingObjList.allocData :Pointer;
- begin
- GetMem(Result, sizeof(TLuaExistingObjListData));
- fillchar(Result^, sizeof(TLuaExistingObjListData), 0);
- end;
- procedure TLuaExistingObjList.deallocData(pData :Pointer);
- begin
- PLuaExistingObjListData(pData)^.Name :='';
- FreeMem(pData, sizeof(TLuaExistingObjListData));
- end;
- function TLuaExistingObjList.Add(Obj :TObject; Name :String) :PLuaExistingObjListData;
- begin
- Result :=Find(Name);
- if (Result=nil)
- then Result :=Self.Add;
- if (Result<>nil)
- then begin
- Result^.Obj :=Obj;
- Result^.Name :=Uppercase(Name);
- end;
- end;
- function TLuaExistingObjList.Find(Name :String) :PLuaExistingObjListData;
- function CompByClass(Tag :Integer; ptData1, ptData2 :Pointer) :Boolean;
- begin
- Result := String(PChar(ptData1)) = PLuaExistingObjListData(ptData2)^.Name;
- end;
- begin
- Result :=Self.ExtFind(PChar(Uppercase(Name)), 0, @CompByClass);
- end;
- //==============================================================================
- function GetPropertyArrayObject(var Data : TLuaArrayPropData; L: Plua_State; Index: Integer): boolean; forward;
- function LuaPush_TLuaObject(L :Plua_State; theParams :array of Variant;
- Obj :TObject=nil; ObjClassName :String='';
- CanFree :Boolean=True) :boolean; forward;
- function LuaPushPropertyArrayObject(L: Plua_State; Obj :TLuaObject; PropName :string): boolean; forward;
- function LuaPushPropertySet(L: Plua_State; TypeInfo :PTypeInfo; PropValue :Variant): boolean; forward;
- function PushProperty(L :Plua_State; scripter :TLuaObject;
- PropName :string; PropValue :Variant; PropType :PTypeInfo) :Integer;
- begin
- Result :=0;
- if (PropType^.Kind = tkClass)
- then begin
- //If this property is a class, push a TLuaObject in the stack
- if LuaPush_TLuaObject(L, [], TObject(Integer(PropValue)))
- then Result := 1;
- end
- else
- if (PropType^.Kind =tkArray)
- then begin //If this property is an array, push an ArrayPropObject in the stack
- if LuaPushPropertyArrayObject(L, scripter, PropName)
- then Result := 1;
- end
- else
- if (PropType^.Kind =tkSet)
- then begin //If this property is an array, push an ArrayPropObject in the stack
- if LuaPushPropertySet(L, PropType, PropValue)
- then Result := 1;
- end
- else
- begin //Push the PropValue
- LuaPushVariant(L, PropValue);
- Result := 1;
- end;
- end;
- //==============================================================================
- // Array Properties Support
- function Lua_IsPropertyArrayObject(L: Plua_State; Index: Integer): boolean;
- begin
- Result :=False;
- try
- Result :=(LuaGetTableString(L, Index, 'ID')=ARRAYPROP_STR);
- except
- end;
- end;
- function GetPropertyArrayObject(var Data : TLuaArrayPropData; L: Plua_State; Index: Integer): boolean;
- begin
- Result :=false;
- try
- Data.Obj :=TLuaObject(LuaGetTableLightUserData(L, Index, ARRAYPROP_STR));
- Data.PropName :=LuaGetTableString(L, Index, ARRAYPROPNAME_STR);
- Result :=true;
- except
- end;
- end;
- function Lua_ArrayProp_Get(L: Plua_State): Integer; cdecl;
- Var
- indice,
- PropValue :Variant;
- PropType :PTypeInfo;
- GetPropOK :Boolean;
- NParams :Integer;
- Data :TLuaArrayPropData;
- begin
- Result := 0;
- NParams := lua_gettop(L);
- if (NParams=2) then
- try
- GetPropertyArrayObject(Data, L, 1);
- indice :=LuaToVariant(L, 2);
- if (indice<>NULL)
- then begin
- PropType :=Data.Obj.GetArrayPropType(Data.PropName, indice);
- GetPropOK := (PropType<>nil);
- if GetPropOK
- then PropValue :=Data.Obj.GetArrayProp(Data.PropName, indice)
- else PropValue :=NULL;
- Result :=PushProperty(L, Data.Obj, Data.PropName, PropValue, PropType);
- end
- else raise Exception.CreateFmt('Trying to index %s.%s with a NULL index', [Data.Obj.InstanceObj.ClassName, Data.PropName]);
- except
- On E:Exception do begin
- LuaError(L, ERR_Script+E.Message);
- end;
- end;
- end;
- function Lua_ArrayProp_Set(L: Plua_State): Integer; cdecl;
- begin
- end;
- function LuaPushPropertyArrayObject(L: Plua_State; Obj :TLuaObject; PropName :string): boolean;
- begin
- lua_newtable(L);
- LuaSetTableString(L, -1, 'ID', ARRAYPROP_STR);
- LuaSetTableLightUserData(L, -1, ARRAYPROP_STR, Obj);
- LuaSetTableString(L, -1, ARRAYPROPNAME_STR, PropName);
- LuaSetTablePropertyFuncs(L, -1, Lua_ArrayProp_Get, Lua_ArrayProp_Set);
- Result :=true;
- end;
- //==============================================================================
- //Set Properties Support
- function Lua_IsPropertySet(L: Plua_State; Index: Integer): boolean;
- begin
- Result :=False;
- try
- Result :=lua_istable(L, Index) and (LuaGetTableString(L, Index, 'ID')=SETPROP_VALUE);
- except
- end;
- end;
- function GetPropertySet(Data :PLuaSetPropData; L: Plua_State; Index: Integer): String;
- begin
- Result :='';
- if Data<>nil then FillChar(Data^, Sizeof(TLuaSetPropData), 0);
-
- try
- if lua_istable(L, Index)
- then begin
- Result :=LuaGetTableString(L, Index, SETPROP_VALUE);
- if Data<>nil then
- begin
- Data^.ID :=LuaGetTableString(L, Index, 'ID');
- Data^.Info :=LuaGetTableLightUserData(L, Index, SETPROP_INFO);
- end;
- end
- else begin
- if (lua_isString(L, Index)=1)
- then Result :=LuaToString(L, Index);
- end;
- if Data<>nil
- then Data^.Value :=Result;
- except
- end;
- end;
- function SetToString(TypeInfo: PTypeInfo; Value: Integer; Brackets: Boolean): string;
- var
- S: TIntegerSet;
- I: Integer;
- EnumInfo :PTypeInfo;
- begin
- Result := '';
- Integer(S) := Value;
- EnumInfo := GetTypeData(TypeInfo)^.CompType^;
- for I := 0 to SizeOf(Integer) * 8 - 1 do
- if I in S then
- begin
- if Result <> '' then
- Result := Result + ',';
- Result := Result + GetEnumName(EnumInfo, I);
- end;
- if Brackets then
- Result := '[' + Result + ']';
- end;
- // grab the next enum name
- function SetNextWord(var P: PChar): string;
- var
- i: Integer;
- begin
- i := 0;
- // scan til whitespace
- while not (P[i] in [',', ' ', #0,']']) do
- Inc(i);
- SetString(Result, P, i);
- // skip whitespace
- while P[i] in [',', ' ',']'] do
- Inc(i);
- Inc(P, i);
- end;
- function StringToSet(EnumInfo: PTypeInfo; const Value: string): Integer;
- var
- P: PChar;
- EnumName: string;
- EnumValue: Longint;
- begin
- Result := 0;
- if Value = '' then Exit;
- P := PChar(Value);
- // skip leading bracket and whitespace
- while P^ in ['[',' '] do
- Inc(P);
- EnumName := SetNextWord(P);
- while EnumName <> '' do
- begin
- EnumValue := GetEnumValue(EnumInfo, EnumName);
- if EnumValue < 0 then
- raise EPropertyConvertError.CreateFmt('Invalid Property Element %s', [EnumName]);
- Include(TIntegerSet(Result), EnumValue);
- EnumName := SetNextWord(P);
- end;
- end;
- function Lua_SetProp_Add(L: Plua_State): Integer; cdecl;
- Var
- Val1, Val2,
- EnumName,
- xResult :String;
- NParams :Integer;
- pVal2 :PChar;
- begin
- Result := 0;
- NParams := lua_gettop(L);
- if (NParams=2) then
- try
- Val1 :=GetPropertySet(nil, L, 1);
- if (Val1='')
- then raise Exception.Create('Left Side is Not a Set');
- Val2 :=GetPropertySet(nil, L, 2);
- if (Val2='')
- then raise Exception.Create('Right Side is Not a Set');
- xResult :=Val1;
- pVal2 :=PChar(Val2);
- EnumName := SetNextWord(pVal2);
- while (EnumName<>'') do
- begin
- if (Pos(EnumName, Val1)<1)
- then xResult :=xResult+','+EnumName;
- EnumName := SetNextWord(pVal2);
- end;
- LuaPushPropertySet(L, nil, xResult);
- Result :=1;
- except
- On E:Exception do begin
- LuaError(L, ERR_Script+E.Message);
- end;
- end;
- end;
- function Lua_SetProp_Sub(L: Plua_State): Integer; cdecl;
- Var
- Val1, Val2,
- EnumName,
- xResult :String;
- NParams :Integer;
- pVal2 :PChar;
- xPos :Integer;
- begin
- Result := 0;
- NParams := lua_gettop(L);
- if (NParams=2) then
- try
- Val1 :=GetPropertySet(nil, L, 1);
- if (Val1='')
- then raise Exception.Create('Left Side is Not a Set');
- Val2 :=GetPropertySet(nil, L, 2);
- if (Val1='')
- then raise Exception.Create('Right Side is Not a Set');
- xResult :=Val1;
- pVal2 :=PChar(Val2);
- EnumName := SetNextWord(pVal2);
- while (EnumName<>'') do
- begin
- xPos := Pos(EnumName, xResult);
- while (xPos>0) do
- begin
- Delete(xResult, xPos, Length(EnumName)+1);
- xPos := Pos(EnumName, xResult);
- end;
- EnumName := SetNextWord(pVal2);
- end;
- LuaPushPropertySet(L, nil, xResult);
- Result :=1;
- except
- On E:Exception do begin
- LuaError(L, ERR_Script+E.Message);
- end;
- end;
- end;
- function LuaPushPropertySet(L: Plua_State; TypeInfo :PTypeInfo; PropValue :Variant): boolean;
- begin
- lua_newtable(L);
- LuaSetTableString(L, -1, 'ID', SETPROP_INFO);
- LuaSetTableLightUserData(L, -1, SETPROP_INFO, TypeInfo);
- if (TVarData(PropValue).VType = varString) or
- (TVarData(PropValue).VType = varOleStr)
- then LuaSetTableString(L, -1, SETPROP_VALUE, PropValue)
- else LuaSetTableString(L, -1, SETPROP_VALUE, SetToString(TypeInfo, PropValue, false));
- LuaSetMetaFunction(L, -1, '__add', Lua_SetProp_Add);
- LuaSetMetaFunction(L, -1, '__sub', Lua_SetProp_Sub);
- Result :=true;
- end;
- //==============================================================================
- function GetTLuaObject(L: Plua_State; Index: Integer): TLuaObject;
- Var
- pObjData :PLuaObjectData;
- begin
- //Result := TLuaObject(LuaGetTableLightUserData(L, Index, OBJHANDLE_STR));
- Result :=nil;
- try
- if (lua_isuserdata(L, Index)=1) then
- begin
- pObjData :=lua_touserdata(L, Index);
- if (pObjData^.ID=OBJHANDLE_STR)
- then Result :=pObjData^.Obj;
- end;
- except
- end;
- end;
- //=== Methods Access methods ===================================================
- function Lua_TObject_Methods(L: Plua_State): Integer; cdecl;
- var
- NParams,
- iParams,
- invParams :Integer;
- theParams :array of Variant;
- xResult :Variant;
- ParamISOBJ :Boolean;
- MethodName :String;
- curComponent :TObject;
- NewObj,
- LuaObj :TLuaObject;
- PropSetData :TLuaSetPropData;
- retValue :Variant;
- begin
- Result :=0;
- NParams := lua_gettop(L);
- try
- LuaObj :=GetTLuaObject(L, 1);
- MethodName :=LuaGetCurrentFuncName(L);
- //Fill Params for Method call in inverse sequense (why???)
- SetLength(theParams, (NParams-1));
- invParams :=0;
- for iParams :=NParams downto 2 do
- begin
- //If Param[iParams] is an Object get it's real value
- ParamISOBJ :=false;
- NewObj :=GetTLuaObject(L, iParams);
- ParamISOBJ :=(NewObj<>nil);
- if ParamISOBJ
- then xResult :=Integer(NewObj.InstanceObj)
- else begin
- if Lua_IsPropertySet(L, iParams)
- then begin
- xResult :=GetPropertySet(@PropSetData, L, iParams);
- //try to convert string value to Real Set Value
- if (PropSetData.Info<>nil)
- then xResult :=StringToSet(PropSetData.Info, xResult);
- end
- else xResult :=LuaToVariant(L, iParams);
- end;
- theParams[invParams] :=xResult;
- inc(invParams);
- end;
- retValue := LuaObj.CallMethod(MethodName, theParams, true);
- if (retValue<>NULL)
- then begin
- //TO-DO : PushVariant è riduttivo, potrebbe tornare un oggetto etc...
- // Fare una procedura simile a PushProperty
- LuaPushVariant(L, retValue);
- Result :=1;
- end;
- except
- On E:Exception do begin
- LuaError(L, ERR_Script+E.Message);
- end;
- end;
- end;
- function Lua_TObject_GetProp(L: Plua_State): Integer; cdecl; forward;
- function Lua_TObject_SetProp(L: Plua_State): Integer; cdecl; forward;
- function Lua_TObject_Free(L: Plua_State): Integer; cdecl; forward;
- function LuaPush_TLuaObject(L :Plua_State; theParams :array of Variant;
- Obj :TObject=nil; ObjClassName :String='';
- CanFree :Boolean=True) :boolean;
- var
- NParams,
- iParams :Integer;
- xResult :Variant;
- retValue :Variant;
- ClassData :PLuaClassesListData;
- LuaObj :TLuaObject;
- NewObj :TObject;
- CanCreate :Boolean;
- LuaClass :TLuaObjectClass;
- pObjData :PLuaObjectData;
- scripter :TScriptableObject;
- begin
- Result :=false;
- CanCreate := (Obj=nil);
- if CanCreate
- then ClassData :=LuaClassesList.Find(ObjClassName)
- else ClassData :=LuaClassesList.Find(Obj.ClassType);
- if (ClassData=nil)
- then LuaClass :=TLuaObject
- else LuaClass :=ClassData^.LuaClass;
- //lua_newtable(L);
- pObjData :=lua_newuserdata(L, sizeof(TLuaObjectData));
- if CanCreate
- then begin
- if (LuaClass<>nil)
- then begin
- LuaObj :=LuaClass.Create(nil, false);
- theParams[High(theParams)] :=Integer(ClassData^.ObjClass);
-
- try
- retValue :=LuaObj.CallMethod('LuaCreate', theParams, true);
- if (retValue<>NULL)
- then NewObj :=TObject(Integer(retValue))
- else NewObj :=ClassData^.ObjClass.Create;
- except
- NewObj :=ClassData^.ObjClass.Create;
- end;
- LuaObj.Free;
- LuaObj :=LuaClass.Create(NewObj, CanFree);
- end
- else begin
- NewObj :=ClassData^.ObjClass.Create;
- LuaObj :=LuaClass.Create(NewObj, CanFree);
- end;
- end
- else begin
- if (LuaClass<>nil)
- then LuaObj :=LuaClass.Create(Obj, false)
- else LuaObj :=TLuaObject.Create(Obj, false);
- end;
- pObjData^.ID :=OBJHANDLE_STR;
- pObjData^.Obj :=LuaObj;
- LuaSetTablePropertyFuncs(L, -1, Lua_TObject_GetProp, Lua_TObject_SetProp);
- LuaSetMetaFunction(L, -1, '__gc', Lua_TObject_Free);
- Result :=true;
- end;
- //=== Properties Access methods ================================================
- //NON FUNZIONA!!!!!!! PERCHE' FA LA LISTA SOLO DELLE PROPERTY PUBLISHED
- function FindPredefArrayProp(AComponent :TObject):String;
- Var
- Props :PPropList;
- i, n :Integer;
- curPropInfo :PPropInfo;
- begin
- Result :='';
- n :=GetPropList(AComponent, Props);
- for i:=0 to n-1 do
- begin
- curPropInfo :=PPropInfo(Props^[i]);
- if ((curPropInfo^.Default and $80000000)<>0) and
- (curPropInfo^.PropType^^.Kind = tkArray)
- then begin
- Result :=curPropInfo^.Name;
- end;
- end;
- end;
- function Lua_TObject_GetProp(L: Plua_State): Integer; cdecl;
- Var
- ty :Integer;
- PropName :String;
- PropValue :Variant;
- PropInfo :PPropInfo;
- PropType :PTypeInfo;
- GetPropOK :Boolean;
- NParams :Integer;
- ClassData :PLuaClassesListData;
- LuaObj :TLuaObject;
- NewObj :TObject;
- function TryGetProp(AComponent :TObject; PropName :String; PropKind :TTypeKinds):Boolean;
- Var
- AsString :Boolean;
- begin
- Result :=false;
- try
- PropInfo :=GetPropInfo(AComponent, PropName, PropKind);
- if (PropInfo<>nil)
- then begin //This Name is a Property
- PropType :=PropInfo^.PropType^;
- //Return as String only if the property is a Set or an Enum, exclude the Boolean
- if (PropType^.Kind=tkEnumeration)
- then AsString := not(GetTypeData(PropType)^.BaseType^ = TypeInfo(Boolean))
- else AsString := (PropType^.Kind=tkSet);
- PropValue :=GetPropValue(AComponent, PropInfo, AsString);
- Result :=true;
- end;
- except
- end;
- end;
- function TryGetPublicProp:Boolean;
- Var
- AsString :Boolean;
- begin
- Result :=false;
- try
- PropInfo :=LuaObj.GetPublicPropInfo(PropName);
- if (PropInfo<>nil)
- then begin //This Name is a Property
- PropType :=PropInfo^.PropType^;
- //Return as String only if the property is a Set or an Enum, exclude the Boolean
- if (PropType^.Kind=tkEnumeration)
- then AsString := not(GetTypeData(PropType)^.BaseType^ = TypeInfo(Boolean))
- else AsString := (PropType^.Kind=tkSet);
- if (PropType^.Kind<>tkArray)
- then PropValue :=GetPropValue(LuaObj.InstanceObj, PropInfo, AsString);
- Result :=true;
- end;
- except
- end;
- end;
- procedure GetPredefArrayProp(Index: Integer);
- var
- indice :Variant;
- begin
- GetPropOK :=false;
- try
- indice :=LuaToVariant(L, Index);
- PropName :=LuaObj.GetDefaultArrayProp;
- PropType :=LuaObj.GetArrayPropType(PropName, indice);
- GetPropOK := (PropType<>nil);
- except
- end;
- if GetPropOK
- then PropValue :=LuaObj.GetArrayProp(PropName, indice)
- else PropValue :=NULL;
- end;
- begin
- Result := 0;
- GetPropOK := false;
- NParams := lua_gettop(L);
- if (NParams>0) then
- try
- LuaObj :=GetTLuaObject(L, 1);
- ty := lua_type(L, 2);
- if (ty = LUA_TNUMBER)
- then GetPredefArrayProp(2)
- else begin
- PropName :=LuaToString(L, 2);
- GetPropOK :=TryGetProp(LuaObj, PropName, tkProperties);
- if not(GetPropOK)
- then begin //Is not a Property published in the TLuaObject, try the TObject
- GetPropOK :=TryGetProp(LuaObj.InstanceObj, PropName, tkProperties);
- if not(GetPropOK)
- then begin //Try with public Properties using scripter.GetPublicXXX
- GetPropOK :=TryGetPublicProp;
- end;
- if not(GetPropOK)
- then begin //Try with public elements using scripter.GetElementXXX
- try
- PropType :=LuaObj.GetElementType(PropName);
- GetPropOK := (PropType<>nil);
- except
- end;
- if GetPropOK and (PropType^.Kind<>tkArray)
- then PropValue :=LuaObj.GetElement(PropName);
- end;
- end;
- end;
- if (GetPropOK)
- then begin //This Name is a Property
- Result :=PushProperty(L, LuaObj, PropName, PropValue, PropType);
- end
- else begin //This Name may be a Method or an Event ???????????
- //TO-DO : Testare se è un evento (OnXXXX), in questo caso
- // tornare l' eventuale nome della funzione lua
- // (this code is for method)
- LuaRawSetTableNil(L, 1, PropName);
- LuaRawSetTableFunction(L, 1, PropName, Lua_TObject_Methods);
- lua_pushcfunction(L, Lua_TObject_Methods);
- Result := 1;
- end;
- except
- On E:Exception do begin
- LuaError(L, ERR_Script+E.Message);
- end;
- end;
- end;
- // TObject:SetProp(string PropName, variant Value) set Property Value.
- function Lua_TObject_SetProp(L: Plua_State): Integer; cdecl;
- Var
- curComponent :TObject;
- ty :Integer;
- PropName :String;
- PropInfo :PPropInfo;
- PropType :PTypeInfo;
- SetPropOK :Boolean;
- NewVal :Variant;
- NParams :Integer;
- ClassData :PLuaClassesListData;
- LuaObj :TLuaObject;
- NewObj :TLuaObject;
- NewValISPropertySet,
- NewValISOBJ :Boolean;
- PropertySetData :TLuaSetPropData;
- function TrySetProp(AComponent :TObject; PropName :String; PropKind :TTypeKinds):Boolean;
- begin
- Result :=false;
- try
- PropInfo :=GetPropInfo(AComponent, PropName, PropKind);
- if (PropInfo<>nil)
- then begin //This Name is a Property
- curComponent :=AComponent;
- PropType :=PropInfo^.PropType^;
- Result :=true;
- end;
- except
- end;
- end;
- function TrySetPublicProp:Boolean;
- begin
- Result :=false;
- try
- PropInfo :=LuaObj.GetPublicPropInfo(PropName);
- if (PropInfo<>nil)
- then begin //This Name is a Property
- curComponent :=LuaObj.InstanceObj;
- PropType :=PropInfo^.PropType^;
- Result :=true;
- end;
- except
- end;
- end;
- procedure SetPredefArray(Index: Integer);
- var
- indice :Variant;
- begin
- indice :=LuaToVariant(L, Index);
- PropName :=LuaObj.GetDefaultArrayProp;
- PropType :=LuaObj.GetArrayPropType(PropName, indice);
- if (PropType^.Kind=tkClass)
- then begin
- if NewValISOBJ
- then LuaObj.SetArrayProp(PropName, indice, Integer(NewObj.InstanceObj))
- else raise Exception.Createfmt('Cannot assign %s to %s.%s', [NewVal, curComponent.ClassName, PropName]);
- end
- else LuaObj.SetArrayProp(PropName, indice, NewVal);
- end;
- begin
- Result := 0;
- ty :=lua_type(L, 3);
- if (ty <> LUA_TFUNCTION) then
- try
- LuaObj :=GetTLuaObject(L, 1);
- //If the new Value is an Object get it's real value
- NewValISOBJ :=false;
- NewObj :=GetTLuaObject(L, 3);
- NewValISOBJ :=(NewObj<>nil);
- if not(NewValISOBJ)
- then begin
- NewValISPropertySet :=Lua_IsPropertySet(L, 3);
- if NewValISPropertySet
- then NewVal :=GetPropertySet(@PropertySetData, L, 3)
- else NewVal :=LuaToVariant(L, 3);
- end;
- ty := lua_type(L, 2);
- if (ty = LUA_TNUMBER)
- then SetPredefArray(2)
- else begin
- PropName :=LuaToString(L, 2);
- SetPropOK :=TrySetProp(LuaObj, PropName, tkProperties);
- if not(SetPropOK)
- then begin //Is not a Property published in the TLuaObject, try the TObject
- SetPropOK :=TrySetProp(LuaObj.InstanceObj, PropName, tkProperties);
- if not(SetPropOK)
- then begin //Try with public Properties using scripter.GetPublicPropInfo
- SetPropOK :=TrySetPublicProp;
- end;
- if not(SetPropOK)
- then begin //Try with public elements using scripter.SetElementXXX
- try
- PropType :=LuaObj.GetElementType(PropName);
- SetPropOK := (PropType<>nil);
- except
- end;
- if SetPropOK then
- begin
- if (PropType^.Kind=tkClass)
- then begin
- if NewValISOBJ
- then LuaObj.SetElement(PropName, Integer(NewObj.InstanceObj))
- else raise Exception.Createfmt('Cannot assign %s to %s.%s', [NewVal, LuaObj.InstanceObj.ClassName, PropName]);
- end
- else begin
- if NewValISPropertySet //convert string to real Value
- then NewVal :=StringToSet(PropertySetData.Info, NewVal);
- LuaObj.SetElement(PropName, NewVal);
- end;
- Exit;
- end;
- end;
- end;
- if SetPropOK
- then begin
- if (PropType^.Kind=tkClass)
- then begin
- if NewValISOBJ
- then MySetPropValue(curComponent, PropInfo, Integer(NewObj.InstanceObj))
- else raise Exception.Createfmt('Cannot assign %s to %s.%s', [NewVal, curComponent.ClassName, PropName]);
- end
- else MySetPropValue(curComponent, PropInfo, NewVal);
- end
- else begin //This Name may be a Method or an Event ???????????
- //TO-DO : se è un evento potremmo mantenere una Lista
- // che associa un oggetto con il nome di una
- // funzione Lua. Settiamo come evento un
- // nostro metodo che cerca nella Lista l' oggetto
- // e chiama la relativa funzione lua
- end;
- end;
- except
- On E:Exception do begin
- LuaError(L, ERR_Script+E.Message);
- end;
- end;
- end;
- // TObject:Free() free the object.
- function Lua_TObject_Free(L: Plua_State): Integer; cdecl;
- Var
- theObject :TLuaObject;
- NParams :Integer;
- begin
- Result := 0;
- NParams := lua_gettop(L);
- if (NParams=1)
- then begin
- try
- theObject :=GetTLuaObject(L, 1);
- //LuaEventsList.Del(theObject.InstanceObj);
- theObject.Free;
- //LuaSetTableClear(L, 1);
- except
- On E:Exception do begin
- LuaError(L, ERR_Script+E.Message);
- end;
- end;
- end;
- end;
- //==============================================================================
- // Main Functions
- function Lua_CreateObject(L: Plua_State): Integer; cdecl;
- var
- NParams,
- iParams,
- invParams :Integer;
- theParams :array of Variant;
- xResult :Variant;
- retValue :PVariant;
- ObjClassName :String;
- ClassData :PLuaClassesListData;
- scripter :TLuaObject;
- NewObj :TLuaObject;
- CanFree,
- ParamISOBJ :Boolean;
- PropSetData :TLuaSetPropData;
- begin
- Result :=0;
- NParams := lua_gettop(L);
- if (NParams>1)
- then begin
- try
- ObjClassName :=LuaToString(L, 1);
- CanFree :=LuaToBoolean(L, 2);
- //Fill Params for Create call in inverse sequense (why???)
- SetLength(theParams, NParams-1);
- invParams :=0;
- for iParams :=NParams downto 3 do
- begin
- //If Param[iParams] is an Object get it's real value
- ParamISOBJ :=false;
- NewObj :=GetTLuaObject(L, iParams);
- ParamISOBJ :=(NewObj<>nil);
- if ParamISOBJ
- then xResult :=Integer(NewObj.InstanceObj)
- else begin
- if Lua_IsPropertySet(L, iParams)
- then begin
- xResult :=GetPropertySet(@PropSetData, L, iParams);
- //try to convert string value to Real Set Value
- if (PropSetData.Info<>nil)
- then xResult :=StringToSet(PropSetData.Info, xResult);
- end
- else xResult :=LuaToVariant(L, iParams);
- end;
-
- theParams[invParams] :=xResult;
- inc(invParams);
- end;
- //LuaPush_TLuaObject sets the last parameter with the Class
- theParams[invParams] :=1234;
- if LuaPush_TLuaObject(L, theParams, nil, ObjClassName, CanFree)
- then Result :=1
- else raise Exception.Createfmt('Cannot Create class %s', [ObjClassName])
- except
- On E:Exception do begin
- LuaError(L, ERR_Script+E.Message);
- end;
- end;
- end;
- end;
- function Lua_GetObject(L: Plua_State): Integer; cdecl;
- var
- NParams,
- iParams,
- invParams :Integer;
- theParams :array of Variant;
- xResult :Variant;
- retValue :PVariant;
- ObjName :String;
- ObjData :PLuaExistingObjListData;
- scripter :TLuaObject;
- NewObj :TObject;
- begin
- Result :=0;
- NParams := lua_gettop(L);
- if (NParams>0)
- then begin
- try
- ObjName :=LuaToString(L, 1);
- ObjData := LuaExistingObjList.Find(ObjName);
- if (ObjData<>nil)
- then begin
- if LuaPush_TLuaObject(L, [], ObjData^.Obj)
- then Result :=1
- else raise Exception.Createfmt('Cannot Interface with class %s', [ObjData^.Obj.ClassName]);
- end
- else raise Exception.Createfmt('Object "%s" not found', [ObjName]);
- except
- On E:Exception do begin
- LuaError(L, ERR_Script+E.Message);
- end;
- end;
- end;
- end;
- procedure RegisterFunctions(L: Plua_State);
- begin
- LuaRegister(L, 'CreateObject', Lua_CreateObject);
- LuaRegister(L, 'GetObject', Lua_GetObject);
- end;
- procedure RegisterClass(ObjClass :TClass; LuaClass :TLuaObjectClass=nil);
- begin
- LuaClassesList.Add(ObjClass, LuaClass);
- end;
- procedure RegisterObject(Obj :TObject; Name :String; LuaClass :TLuaObjectClass=nil);
- begin
- LuaExistingObjList.Add(Obj, Name);
- LuaClassesList.Add(Obj.ClassType, LuaClass);
- end;
- initialization
- LuaClassesList :=TLuaClassesList.Create;
- LuaExistingObjList :=TLuaExistingObjList.Create;
- finalization
- LuaClassesList.Free;
- LuaExistingObjList.Free;
- end.
|