📄 jclrtti.pas
字号:
if ifDispInterface in Flags then
Dest.Write('dispinterface')
else
Dest.Write('interface');
if (Parent <> nil) and not (ifDispInterface in Flags) and not
AnsiSameText(Parent.Name, 'IUnknown') then
Dest.Write('(' + Parent.Name + ')');
Dest.Writeln(' // unit ' + UnitName);
Dest.Indent;
try
if ifHasGuid in Flags then
Dest.Writeln('[''' + JclGuidToString(GUID) + ''']');
finally
Dest.Outdent;
Dest.Writeln('end;');
end;
end;
//=== { TJclInt64TypeInfo } ==================================================
type
TJclInt64TypeInfo = class(TJclTypeInfo, IJclInt64TypeInfo)
protected
function GetMinValue: Int64;
function GetMaxValue: Int64;
procedure WriteTo(const Dest: IJclInfoWriter); override;
procedure DeclarationTo(const Dest: IJclInfoWriter); override;
public
property MinValue: Int64 read GetMinValue;
property MaxValue: Int64 read GetMaxValue;
end;
function TJclInt64TypeInfo.GetMinValue: Int64;
begin
Result := TypeData.MinInt64Value;
end;
function TJclInt64TypeInfo.GetMaxValue: Int64;
begin
Result := TypeData.MaxInt64Value;
end;
procedure TJclInt64TypeInfo.WriteTo(const Dest: IJclInfoWriter);
begin
inherited WriteTo(Dest);
Dest.Writeln(LoadResString(@RsRTTIMinValue) + IntToStr(MinValue));
Dest.Writeln(LoadResString(@RsRTTIMaxValue) + IntToStr(MaxValue));
end;
procedure TJclInt64TypeInfo.DeclarationTo(const Dest: IJclInfoWriter);
begin
Dest.Writeln(Name + ' = ' + IntToStr(MinValue) + ' .. ' + IntToStr(MaxValue) + ';');
end;
//=== { TJclDynArrayTypeInfo } ===============================================
{$IFDEF COMPILER6_UP}
type
TJclDynArrayTypeInfo = class(TJclTypeInfo, IJclDynArrayTypeInfo)
protected
function GetElementSize: Longint;
function GetElementType: IJclTypeInfo;
function GetElementsNeedCleanup: Boolean;
function GetVarType: Integer;
function GetUnitName: string;
procedure WriteTo(const Dest: IJclInfoWriter); override;
procedure DeclarationTo(const Dest: IJclInfoWriter); override;
public
property ElementSize: Longint read GetElementSize;
property ElementType: IJclTypeInfo read GetElementType;
property ElementsNeedCleanup: Boolean read GetElementsNeedCleanup;
property VarType: Integer read GetVarType;
property UnitName: string read GetUnitName;
end;
function TJclDynArrayTypeInfo.GetElementSize: Longint;
begin
Result := TypeData.elSize;
end;
function TJclDynArrayTypeInfo.GetElementType: IJclTypeInfo;
begin
if TypeData.elType = nil then
begin
if TypeData.elType2 <> nil then
Result := JclTypeInfo(TypeData.elType2^)
else
Result := nil;
end
else
Result := JclTypeInfo(TypeData.elType^);
end;
function TJclDynArrayTypeInfo.GetElementsNeedCleanup: Boolean;
begin
Result := TypeData.elType <> nil;
end;
function TJclDynArrayTypeInfo.GetVarType: Integer;
begin
Result := TypeData.varType;
end;
function TJclDynArrayTypeInfo.GetUnitName: string;
begin
Result := TypeData.DynUnitName;
end;
procedure TJclDynArrayTypeInfo.WriteTo(const Dest: IJclInfoWriter);
begin
inherited WriteTo(Dest);
Dest.Writeln(LoadResString(@RsRTTIElSize) + IntToStr(ElementSize));
if ElementType = nil then
Dest.Writeln(LoadResString(@RsRTTIElType) + LoadResString(@RsRTTITypeError))
else
if ElementType.Name[1] <> '.' then
Dest.Writeln(LoadResString(@RsRTTIElType) + ElementType.Name)
else
begin
Dest.Writeln(LoadResString(@RsRTTIElType));
Dest.Indent;
try
ElementType.WriteTo(Dest);
finally
Dest.Outdent;
end;
end;
Dest.Write(LoadResString(@RsRTTIElNeedCleanup));
if ElementsNeedCleanup then
Dest.Writeln(LoadResString(@RsRTTITrue))
else
Dest.Writeln(LoadResString(@RsRTTIFalse));
Dest.Writeln(LoadResString(@RsRTTIVarType) + IntToStr(VarType));
Dest.Writeln(LoadResString(@RsRTTIUnitName) + UnitName);
end;
procedure TJclDynArrayTypeInfo.DeclarationTo(const Dest: IJclInfoWriter);
begin
if Name[1] <> '.' then
Dest.Write(Name + ' = ' + LoadResString(@RsRTTIArrayOf))
else
Dest.Write(LoadResString(@RsRTTIArrayOf));
if ElementType = nil then
Dest.Write(LoadResString(@RsRTTITypeError))
else
if ElementType.Name[1] = '.' then
ElementType.DeclarationTo(Dest)
else
Dest.Write(ElementType.Name);
if Name[1] <> '.' then
Dest.Writeln('; // Unit ' + UnitName);
end;
{$ENDIF COMPILER6_UP}
//=== Typeinfo retrieval =====================================================
function JclTypeInfo(ATypeInfo: PTypeInfo): IJclTypeInfo;
begin
case ATypeInfo.Kind of
tkInteger, tkChar, tkWChar:
Result := TJclOrdinalRangeTypeInfo.Create(ATypeInfo);
tkEnumeration:
Result := TJclEnumerationTypeInfo.Create(ATypeInfo);
tkSet:
Result := TJclSetTypeInfo.Create(ATypeInfo);
tkFloat:
Result := TJclFloatTypeInfo.Create(ATypeInfo);
tkString:
Result := TJclStringTypeInfo.Create(ATypeInfo);
tkClass:
Result := TJclClassTypeInfo.Create(ATypeInfo);
tkMethod:
Result := TJclEventTypeInfo.Create(ATypeInfo);
tkInterface:
Result := TJclInterfaceTypeInfo.Create(ATypeInfo);
tkInt64:
Result := TJclInt64TypeInfo.Create(ATypeInfo);
{$IFDEF COMPILER6_UP}
tkDynArray:
Result := TJclDynArrayTypeInfo.Create(ATypeInfo);
{$ENDIF COMPILER6_UP}
else
Result := TJclTypeInfo.Create(ATypeInfo);
end;
end;
//=== User generated type info managment =====================================
var
TypeList: TThreadList;
type
PTypeItem = ^TTypeItem;
TTypeItem = record
TypeInfo: PTypeInfo;
RefCount: Integer;
end;
procedure FreeTypeData(const TypeInfo: PTypeInfo);
var
TD: PTypeData;
begin
TD := GetTypeData(TypeInfo);
if TypeInfo.Kind = tkSet then
RemoveTypeInfo(TD^.CompType^)
else
if (TypeInfo.Kind = tkEnumeration) and (TD^.BaseType^ <> TypeInfo) then
RemoveTypeInfo(GetTypeData(TypeInfo)^.BaseType^);
FreeMem(GetTypeData(TypeInfo)^.BaseType);
FreeMem(TypeInfo);
end;
procedure AddType(const TypeInfo: PTypeInfo);
var
Item: PTypeItem;
begin
New(Item);
try
Item.TypeInfo := TypeInfo;
Item.RefCount := 1;
TypeList.Add(Item);
except
Dispose(Item);
raise;
end;
end;
procedure DeleteType(const TypeItem: PTypeItem);
begin
FreeTypeData(TypeItem.TypeInfo);
TypeList.Remove(TypeItem);
Dispose(TypeItem);
end;
procedure DoRefType(const TypeInfo: PTypeInfo; Add: Integer);
var
I: Integer;
List: TList;
begin
List := TypeList.LockList;
try
I := List.Count-1;
while (I >= 0) and (PTypeItem(List[I]).TypeInfo <> TypeInfo) do
Dec(I);
if I > -1 then
Inc(PTypeItem(List[I]).RefCount, Add);
finally
TypeList.UnlockList;
end;
end;
procedure ReferenceType(const TypeInfo: PTypeInfo);
begin
DoRefType(TypeInfo, 1);
end;
procedure DeReferenceType(const TypeInfo: PTypeInfo);
begin
DoRefType(TypeInfo, -1);
end;
procedure ClearInfoList;
var
L: TList;
begin
L := TypeList.LockList;
try
while L.Count > 0 do
RemoveTypeInfo(PTypeItem(L[L.Count-1])^.TypeInfo);
finally
TypeList.UnlockList;
end;
end;
procedure NewInfoItem(const TypeInfo: PTypeInfo);
begin
TypeList.Add(TypeInfo);
end;
procedure RemoveTypeInfo(TypeInfo: PTypeInfo);
var
I: Integer;
List: TList;
Item: PTypeItem;
begin
Item := nil;
List := TypeList.LockList;
try
I := List.Count-1;
while (I >= 0) and (PTypeItem(List[I]).TypeInfo <> TypeInfo) do
Dec(I);
if I > -1 then
Item := PTypeItem(List[I]);
finally
TypeList.UnlockList;
end;
if Item <> nil then
begin
Dec(Item.RefCount);
if Item.RefCount <= 0 then
DeleteType(Item);
end;
end;
//=== Enumerations ===========================================================
function JclEnumValueToIdent(TypeInfo: PTypeInfo; const Value): string;
var
MinEnum: Integer;
MaxEnum: Integer;
EnumVal: Int64;
OrdType: TOrdType;
begin
OrdType := GetTypeData(TypeInfo).OrdType;
MinEnum := GetTypeData(TypeInfo).MinValue;
MaxEnum := GetTypeData(TypeInfo).MaxValue;
case OrdType of
otSByte:
EnumVal := Smallint(Value);
otUByte:
EnumVal := Byte(Value);
otSWord:
EnumVal := Shortint(Value);
otUWord:
EnumVal := Word(Value);
otSLong:
EnumVal := Integer(Value);
otULong:
EnumVal := Longword(Value);
else
EnumVal := 0;
end;
// Check range...
if (EnumVal < MinEnum) or (EnumVal > MaxEnum) then
Result := Format(LoadResString(@RsRTTIValueOutOfRange),
[LoadResString(@RsRTTIOrdinal) + IntToStr(EnumVal)])
else
Result := GetEnumName(TypeInfo, EnumVal);
end;
function JclGenerateEnumType(const TypeName: ShortString;
const Literals: array of string): PTypeInfo;
type
PInteger = ^Integer;
var
StringSize: Integer;
I: Integer;
TypeData: PTypeData;
CurName: PShortString;
begin
StringSize := 0;
for I := Low(Literals) to High(Literals) do
StringSize := StringSize + 1 + Length(Literals[I]);
Result := AllocMem(SizeOf(TTypeInfo) + SizeOf(TOrdType) +
(2*SizeOf(Integer)) + SizeOf(PPTypeInfo) +
StringSize {$IFDEF COMPILER6_UP}+ 1{$ENDIF COMPILER6_UP});
try
with Result^ do
begin
Kind := tkEnumeration;
Name := TypeName;
end;
TypeData := GetTypeData(Result);
TypeData^.BaseType := AllocMem(SizeOf(Pointer));
if Length(Literals) < 256 then
TypeData^.OrdType := otUByte
else
if Length(Literals) < 65536 then
TypeData^.OrdType := otUWord
else
TypeData^.OrdType := otULong;
TypeData^.MinValue := 0;
TypeData^.MaxValue := Length(Literals)-1;
TypeData^.BaseType^ := Result; // No sub-range: basetype points to itself
CurName := @TypeData^.NameList;
for I := Low(Literals) to High(Literals) do
begin
CurName^ := Literals[I];
Inc(Integer(CurName), Length(Literals[I])+1);
end;
{$IFDEF COMPILER6_UP}
CurName^ := ''; // Unit name unknown
{$ENDIF COMPILER6_UP}
AddType(Result);
except
try
ReallocMem(Result, 0);
except
Result := nil;
end;
raise;
end;
end;
function JclGenerateEnumTypeBasedOn(const TypeName: ShortString;
BaseType: PTypeInfo; const PrefixCut: Byte): PTypeInfo;
var
BaseInfo: IJclTypeInfo;
BaseKind: TTypeKind;
Literals: array of string;
I: Integer;
S: string;
begin
BaseInfo := JclTypeInfo(BaseType);
BaseKind := BaseInfo.TypeKind;
if BaseInfo.TypeKind <> tkEnumeration then
raise EJclRTTIError.CreateResFmt(@RsRTTIInvalidBaseType, [BaseInfo.Name,
JclEnumValueToIdent(System.TypeInfo(TTypeKind), BaseKind)]);
with BaseInfo as IJclEnumerationTypeInfo do
begin
SetLength(Literals, MaxValue - MinValue + 1);
for I := MinValue to MaxValue do
begin
S := Names[I];
if PrefixCut = PREFIX_CUT_LOWERCASE then
while (Length(S) > 0) and (S[1] in AnsiLowercaseLetters) do
Delete(S, 1, 1);
if (PrefixCut > 0) and (PrefixCut < MaxPrefixCut) then
Delete(S, 1, PrefixCut);
if S = '' then
S := Names[I];
Literals[I- MinValue] := S;
end;
if PrefixCut = PREFIX_CUT_EQUAL then
begin
S := Literals[High(Literals)];
I := High(Literals)-1;
while (I >= 0) and (S > '') do
begin
while Copy(Literals[I], 1, Length(S)) <> S do
Delete
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -