pas2js/packages/rtl/typinfo.pas
2022-02-06 13:42:35 +00:00

1579 lines
48 KiB
ObjectPascal

{
This file is part of the Pas2JS run time library.
Copyright (c) 2018 by Mattias Gaertner
See the file COPYING.FPC, included in this distribution,
for details about the copyright.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
**********************************************************************}
unit TypInfo;
{$mode objfpc}
{$modeswitch externalclass}
interface
uses
SysUtils, Types, RTLConsts, JS;
type
// TCallConv for compatibility with Delphi/FPC, ignored under pas2js
TCallConv = (ccReg, ccCdecl, ccPascal, ccStdCall, ccSafeCall, ccCppdecl,
ccFar16, ccOldFPCCall, ccInternProc, ccSysCall, ccSoftFloat, ccMWPascal);
{ TSectionRTTI }
TSectionRTTI = class external name 'rtl.tSectionRTTI'(TJSObject)
end;
{ TTypeInfoModule }
TTypeInfoModule = class external name 'pasmodule'(TJSObject)
public
Name: String external name '$name';
RTTI: TSectionRTTI external name '$rtti';
end;
TTypeInfoAttributes = type TJSValueDynArray;
{ TTypeInfo }
TTypeInfo = class external name 'rtl.tTypeInfo'
public
Name: String external name 'name';
Kind: TTypeKind external name 'kind';
Attributes: TTypeInfoAttributes external name 'attr'; // can be nil
Module: TTypeInfoModule external name '$module'; // can be nil
end;
TTypeInfoClassOf = class of TTypeInfo;
PTypeInfo = Pointer; // for compatibility with Delphi/FPC, under pas2js it is a TTypeInfo
TOrdType = (
otSByte, // 0
otUByte, // 1
otSWord, // 2
otUWord, // 3
otSLong, // 4
otULong, // 5
otSIntDouble, // 6 NativeInt
otUIntDouble // 7 NativeUInt
);
{ TTypeInfoInteger - Kind = tkInteger }
TTypeInfoInteger = class external name 'rtl.tTypeInfoInteger'(TTypeInfo)
public
MinValue: NativeInt external name 'minvalue';
MaxValue: NativeInt external name 'maxvalue';
OrdType : TOrdType external name 'ordtype';
end;
{ TEnumType }
TEnumType = class external name 'anonymous'
private
function GetIntToName(Index: NativeInt): String; external name '[]';
function GetNameToInt(Name: String): NativeInt; external name '[]';
public
property IntToName[Index: NativeInt]: String read GetIntToName;
property NameToInt[Name: String]: NativeInt read GetNameToInt;
end;
{ TTypeInfoEnum - Kind = tkEnumeration }
TTypeInfoEnum = class external name 'rtl.tTypeInfoEnum'(TTypeInfoInteger)
public
// not supported: BaseType: TTypeInfo
EnumType: TEnumType external name 'enumtype';
end;
{ TTypeInfoSet - Kind = tkSet }
TTypeInfoSet = class external name 'rtl.tTypeInfoSet'(TTypeInfo)
public
// not supported: BaseType: TTypeInfo
CompType: TTypeInfo external name 'comptype';
end;
{ TTypeInfoStaticArray - Kind = tkArray }
TTypeInfoStaticArray = class external name 'rtl.tTypeInfoStaticArray'(TTypeInfo)
public
Dims: TIntegerDynArray external name 'dims';
ElType: TTypeInfo external name 'eltype';
end;
{ TTypeInfoDynArray - Kind = tkDynArray }
TTypeInfoDynArray = class external name 'rtl.tTypeInfoDynArray'(TTypeInfo)
public
ElType: TTypeInfo external name 'eltype';
end;
TParamFlag = (
pfVar, // 2^0 = 1
pfConst, // 2^1 = 2
pfOut, // 2^2 = 4
pfArray, // 2^3 = 8
pfAddress, // 2^4 = 16
pfReference // 2^5 = 32
);
TParamFlags = set of TParamFlag;
{ TProcedureParam }
TProcedureParam = class external name 'anonymous'
public
Name: String external name 'name';
TypeInfo: TTypeInfo external name 'typeinfo';
Flags: NativeInt external name 'flags'; // TParamFlags as bit vector
end;
TProcedureParams = array of TProcedureParam;
TProcedureFlag = (
pfStatic, // 2^0 = 1
pfVarargs, // 2^1 = 2
pfExternal, // 2^2 = 4 name may be an expression
pfSafeCall, // 2^3 = 8
pfAsync // 2^4 = 16
);
TProcedureFlags = set of TProcedureFlag;
{ TProcedureSignature }
TProcedureSignature = class external name 'anonymous'
public
Params: TProcedureParams external name 'params'; // can be nil
ResultType: TTypeInfo external name 'resulttype'; // can be nil
Flags: NativeInt external name 'flags'; // TProcedureFlags as bit vector
end;
{ TTypeInfoProcVar - Kind = tkProcVar }
TTypeInfoProcVar = class external name 'rtl.tTypeInfoProcVar'(TTypeInfo)
public
ProcSig: TProcedureSignature external name 'procsig';
end;
{ TTypeInfoRefToProcVar - Kind = tkRefToProcVar }
TTypeInfoRefToProcVar = class external name 'rtl.tTypeInfoRefToProcVar'(TTypeInfoProcVar)
end;
TMethodKind = (
mkProcedure, // 0 default
mkFunction, // 1
mkConstructor, // 2
mkDestructor, // 3
mkClassProcedure,// 4
mkClassFunction // 5
//mkClassConstructor,mkClassDestructor,mkOperatorOverload
);
TMethodKinds = set of TMethodKind;
{ TTypeInfoMethodVar - Kind = tkMethod }
TTypeInfoMethodVar = class external name 'rtl.tTypeInfoMethodVar'(TTypeInfoProcVar)
public
MethodKind: TMethodKind external name 'methodkind';
end;
TTypeMemberKind = (
tmkUnknown, // 0
tmkField, // 1
tmkMethod, // 2
tmkProperty // 3
);
TTypeMemberKinds = set of TTypeMemberKind;
{ TTypeMember }
TTypeMember = class external name 'rtl.tTypeMember'
public
Name: String external name 'name';
Kind: TTypeMemberKind external name 'kind';
Attributes: TTypeInfoAttributes external name 'attr'; // can be nil
end;
TTypeMemberDynArray = array of TTypeMember;
{ TTypeMemberField - Kind = tmkField }
TTypeMemberField = class external name 'rtl.tTypeMemberField'(TTypeMember)
public
TypeInfo: TTypeInfo external name 'typeinfo';
end;
{ TTypeMemberMethod - Kind = tmkMethod }
TTypeMemberMethod = class external name 'rtl.tTypeMemberMethod'(TTypeMember)
public
MethodKind: TMethodKind external name 'methodkind';
ProcSig: TProcedureSignature external name 'procsig';
end;
TTypeMemberMethodDynArray = array of TTypeMemberMethod;
const
pfGetFunction = 1; // getter is a function
pfSetProcedure = 2; // setter is a procedure
// stored is a 2-bit vector:
pfStoredFalse = 4; // stored false, never
pfStoredField = 8; // stored field, field name is in Stored
pfStoredFunction = 12; // stored function, function name is in Stored
pfHasIndex = 16; { if getter is function, append Index as last param
if setter is function, append Index as second last param }
type
{ TTypeMemberProperty - Kind = tmkProperty }
TTypeMemberProperty = class external name 'rtl.tTypeMemberProperty'(TTypeMember)
public
TypeInfo: TTypeInfo external name 'typeinfo';
Flags: NativeInt external name 'flags'; // bit vector, see pf constants above
Params: TProcedureParams external name 'params'; // can be nil
Index: JSValue external name 'index'; // can be undefined
Getter: String external name 'getter'; // name of field or function
Setter: String external name 'setter'; // name of field or function
Stored: String external name 'stored'; // name of field or function, can be undefined
Default: JSValue external name 'Default'; // can be undefined
end;
TTypeMemberPropertyDynArray = array of TTypeMemberProperty;
{ TTypeMembers }
TTypeMembers = class external name 'rtl.tTypeMembers'
private
function GetItems(Name: String): TTypeMember; external name '[]';
procedure SetItems(Name: String; const AValue: TTypeMember); external name '[]';
public
property Members[Name: String]: TTypeMember read GetItems write SetItems; default;
end;
{ TTypeInfoStruct }
TTypeInfoStruct = class external name 'rtl.tTypeInfoStruct'(TTypeInfo)
private
FFieldCount: NativeInt external name 'fields.length';
FMethodCount: NativeInt external name 'methods.length';
FPropCount: NativeInt external name 'properties.length';
public
Members: TTypeMembers external name 'members';
Names: TStringDynArray external name 'names'; // all member names with TTypeInfo
Fields: TStringDynArray external name 'fields';
Methods: TStringDynArray external name 'methods';
Properties: TStringDynArray external name 'properties';
property FieldCount: NativeInt read FFieldCount;
function GetField(Index: NativeInt): TTypeMemberField; external name 'getField';
function AddField(aName: String; aType: TTypeInfo; Options: TJSObject = nil
): TTypeMemberField; external name 'addField';
property MethodCount: NativeInt read FMethodCount;
function GetMethod(Index: NativeInt): TTypeMemberMethod; external name 'getMethod';
function AddMethod(aName: String; MethodKind: TMethodKind = mkProcedure;
Params: TJSArray = nil; ResultType: TTypeInfo = nil;
Options: TJSObject = nil): TTypeMemberMethod; external name 'addMethod';
property PropCount: NativeInt read FPropCount;
function GetProp(Index: NativeInt): TTypeMemberProperty; external name 'getProperty';
function AddProperty(aName: String; Flags: NativeInt; ResultType: TTypeInfo;
Getter, Setter: String; Options: TJSObject = nil): TTypeMemberProperty; external name 'addProperty';
end;
{ TTypeInfoRecord - Kind = tkRecord }
TTypeInfoRecord = class external name 'rtl.tTypeInfoRecord'(TTypeInfoStruct)
public
RecordType: TJSObject external name '$record'; // only records with class vars, else jsundefined
end;
{ TTypeInfoClass - Kind = tkClass }
TTypeInfoClass = class external name 'rtl.tTypeInfoClass'(TTypeInfoStruct)
public
ClassType: TClass external name 'class';
Ancestor: TTypeInfoClass external name 'ancestor';
end;
{ TTypeInfoExtClass - Kind = tkExtClass }
TTypeInfoExtClass = class external name 'rtl.tTypeInfoExtClass'(TTypeInfo)
public
Ancestor: TTypeInfoExtClass external name 'ancestor';
JSClassName: String external name 'jsclass';
end;
{ TTypeInfoClassRef - class-of, Kind = tkClassRef }
TTypeInfoClassRef = class external name 'rtl.tTypeInfoClassRef'(TTypeInfo)
public
InstanceType: TTypeInfo external name 'instancetype';
end;
{ TTypeInfoPointer - Kind = tkPointer }
TTypeInfoPointer = class external name 'rtl.tTypeInfoPointer'(TTypeInfo)
public
RefType: TTypeInfo external name 'reftype'; // can be null
end;
{ TTypeInfoInterface - Kind = tkInterface }
TTypeInfoInterface = class external name 'rtl.tTypeInfoInterface'(TTypeInfoStruct)
public
InterfaceType: TJSObject external name 'interface';
Ancestor: TTypeInfoInterface external name 'ancestor';
end;
{ TTypeInfoHelper - Kind = tkHelper }
TTypeInfoHelper = class external name 'rtl.tTypeInfoHelper'(TTypeInfoStruct)
public
HelperType: TJSObject external name 'helper';
Ancestor: TTypeInfoHelper external name 'ancestor';
HelperFor: TTypeInfo external name 'helperfor';
end;
EPropertyError = class(Exception);
function GetTypeName(TypeInfo: TTypeInfo): string;
function GetClassMembers(aTIStruct: TTypeInfoStruct): TTypeMemberDynArray;
function GetClassMember(aTIStruct: TTypeInfoStruct; const aName: String): TTypeMember;
function GetInstanceMethod(Instance: TObject; const aName: String): Pointer;
function GetClassMethods(aTIStruct: TTypeInfoStruct): TTypeMemberMethodDynArray;
function CreateMethod(Instance: TObject; FuncName: String): Pointer; external name 'rtl.createCallback';
function GetInterfaceMembers(aTIInterface: TTypeInfoInterface): TTypeMemberDynArray;
function GetInterfaceMember(aTIInterface: TTypeInfoInterface; const aName: String): TTypeMember;
function GetInterfaceMethods(aTIInterface: TTypeInfoInterface): TTypeMemberMethodDynArray;
function GetRTTIAttributes(const Attributes: TTypeInfoAttributes): TCustomAttributeArray;
function GetPropInfos(aTIStruct: TTypeInfoStruct): TTypeMemberPropertyDynArray;
function GetPropList(aTIStruct: TTypeInfoStruct; TypeKinds: TTypeKinds; Sorted: boolean = true): TTypeMemberPropertyDynArray;
function GetPropList(aTIStruct: TTypeInfoStruct): TTypeMemberPropertyDynArray;
function GetPropList(AClass: TClass): TTypeMemberPropertyDynArray;
function GetPropList(Instance: TObject): TTypeMemberPropertyDynArray;
function GetPropInfo(TI: TTypeInfoStruct; const PropName: String): TTypeMemberProperty;
function GetPropInfo(TI: TTypeInfoStruct; const PropName: String; const Kinds: TTypeKinds): TTypeMemberProperty;
function GetPropInfo(Instance: TObject; const PropName: String): TTypeMemberProperty;
function GetPropInfo(Instance: TObject; const PropName: String; const Kinds: TTypeKinds): TTypeMemberProperty;
function GetPropInfo(aClass: TClass; const PropName: String): TTypeMemberProperty;
function GetPropInfo(aClass: TClass; const PropName: String; const Kinds: TTypeKinds): TTypeMemberProperty;
function FindPropInfo(Instance: TObject; const PropName: String): TTypeMemberProperty;
function FindPropInfo(Instance: TObject; const PropName: String; const Kinds: TTypeKinds): TTypeMemberProperty;
function FindPropInfo(aClass: TClass; const PropName: String): TTypeMemberProperty;
function FindPropInfo(aClass: TClass; const PropName: String; const Kinds: TTypeKinds): TTypeMemberProperty;
// Property information routines.
Function IsStoredProp(Instance: TObject; const PropInfo: TTypeMemberProperty): Boolean;
Function IsStoredProp(Instance: TObject; const PropName: string): Boolean;
function IsPublishedProp(Instance: TObject; const PropName: String): Boolean;
function IsPublishedProp(aClass: TClass; const PropName: String): Boolean;
function PropType(Instance: TObject; const PropName: string): TTypeKind;
function PropType(aClass: TClass; const PropName: string): TTypeKind;
function PropIsType(Instance: TObject; const PropName: string; const TypeKind: TTypeKind): Boolean;
function PropIsType(aClass: TClass; const PropName: string; const TypeKind: TTypeKind): Boolean;
function GetJSValueProp(Instance: TJSObject; TI: TTypeInfoStruct; const PropName: String): JSValue;
function GetJSValueProp(Instance: TJSObject; const PropInfo: TTypeMemberProperty): JSValue;
function GetJSValueProp(Instance: TObject; const PropName: String): JSValue;
function GetJSValueProp(Instance: TObject; const PropInfo: TTypeMemberProperty): JSValue;
procedure SetJSValueProp(Instance: TJSObject; TI: TTypeInfoStruct; const PropName: String; Value: JSValue);
procedure SetJSValueProp(Instance: TJSObject; const PropInfo: TTypeMemberProperty; Value: JSValue);
procedure SetJSValueProp(Instance: TObject; const PropName: String; Value: JSValue);
procedure SetJSValueProp(Instance: TObject; const PropInfo: TTypeMemberProperty; Value: JSValue);
function GetNativeIntProp(Instance: TObject; const PropName: String): NativeInt;
function GetNativeIntProp(Instance: TObject; const PropInfo: TTypeMemberProperty): NativeInt;
procedure SetNativeIntProp(Instance: TObject; const PropName: String; Value: NativeInt);
procedure SetNativeIntProp(Instance: TObject; const PropInfo: TTypeMemberProperty; Value: NativeInt);
function GetOrdProp(Instance: TObject; const PropName: String): longint;
function GetOrdProp(Instance: TObject; const PropInfo: TTypeMemberProperty): longint;
procedure SetOrdProp(Instance: TObject; const PropName: String; Value: longint);
procedure SetOrdProp(Instance: TObject; const PropInfo: TTypeMemberProperty; Value: longint);
function GetEnumProp(Instance: TObject; const PropName: String): String;
function GetEnumProp(Instance: TObject; const PropInfo: TTypeMemberProperty): String;
procedure SetEnumProp(Instance: TObject; const PropName: String; const Value: String);
procedure SetEnumProp(Instance: TObject; const PropInfo: TTypeMemberProperty; const Value: String);
// Auxiliary routines, which may be useful
function GetEnumName(TypeInfo: TTypeInfoEnum; Value: Integer): String;
function GetEnumValue(TypeInfo: TTypeInfoEnum; const Name: string): Longint;
function GetEnumNameCount(TypeInfo: TTypeInfoEnum): Longint;
function GetSetProp(Instance: TObject; const PropName: String): String; overload;
function GetSetProp(Instance: TObject; const PropInfo: TTypeMemberProperty): String; overload;
function GetSetPropArray(Instance: TObject; const PropName: String): TIntegerDynArray; overload;
function GetSetPropArray(Instance: TObject; const PropInfo: TTypeMemberProperty): TIntegerDynArray; overload;
procedure SetSetPropArray(Instance: TObject; const PropName: String; const Arr: TIntegerDynArray); overload;
procedure SetSetPropArray(Instance: TObject; const PropInfo: TTypeMemberProperty; const Arr: TIntegerDynArray); overload;
function GetBoolProp(Instance: TObject; const PropName: String): boolean;
function GetBoolProp(Instance: TObject; const PropInfo: TTypeMemberProperty): boolean;
procedure SetBoolProp(Instance: TObject; const PropName: String; Value: boolean);
procedure SetBoolProp(Instance: TObject; const PropInfo: TTypeMemberProperty; Value: boolean);
function GetStrProp(Instance: TObject; const PropName: String): String;
function GetStrProp(Instance: TObject; const PropInfo: TTypeMemberProperty): String;
procedure SetStrProp(Instance: TObject; const PropName: String; Value: String);
procedure SetStrProp(Instance: TObject; const PropInfo: TTypeMemberProperty; Value: String);
function GetStringProp(Instance: TObject; const PropName: String): String; deprecated; // use GetStrProp
function GetStringProp(Instance: TObject; const PropInfo: TTypeMemberProperty): String; deprecated; // use GetStrProp
procedure SetStringProp(Instance: TObject; const PropName: String; Value: String); deprecated; // use GetStrProp
procedure SetStringProp(Instance: TObject; const PropInfo: TTypeMemberProperty; Value: String); deprecated; // use GetStrProp
function GetFloatProp(Instance: TObject; const PropName: string): Double;
function GetFloatProp(Instance: TObject; PropInfo : TTypeMemberProperty) : Double;
procedure SetFloatProp(Instance: TObject; const PropName: string; Value: Double);
procedure SetFloatProp(Instance: TObject; PropInfo : TTypeMemberProperty; Value : Double);
function GetObjectProp(Instance: TObject; const PropName: String): TObject;
function GetObjectProp(Instance: TObject; const PropName: String; MinClass: TClass): TObject;
function GetObjectProp(Instance: TObject; const PropInfo: TTypeMemberProperty): TObject;
function GetObjectProp(Instance: TObject; const PropInfo: TTypeMemberProperty; MinClass: TClass): TObject;
procedure SetObjectProp(Instance: TObject; const PropName: String; Value: TObject) ;
procedure SetObjectProp(Instance: TObject; const PropInfo: TTypeMemberProperty; Value: TObject);
function GetMethodProp(Instance: TObject; PropInfo: TTypeMemberProperty): TMethod;
function GetMethodProp(Instance: TObject; const PropName: string): TMethod;
procedure SetMethodProp(Instance: TObject; PropInfo: TTypeMemberProperty; const Value : TMethod);
procedure SetMethodProp(Instance: TObject; const PropName: string; const Value: TMethod);
function GetInterfaceProp(Instance: TObject; const PropName: string): IInterface;
function GetInterfaceProp(Instance: TObject; PropInfo: TTypeMemberProperty): IInterface;
procedure SetInterfaceProp(Instance: TObject; const PropName: string; const Value: IInterface);
procedure SetInterfaceProp(Instance: TObject; PropInfo: TTypeMemberProperty; const Value: IInterface);
function GetRawInterfaceProp(Instance: TObject; const PropName: string): Pointer;
function GetRawInterfaceProp(Instance: TObject; PropInfo: TTypeMemberProperty): Pointer;
procedure SetRawInterfaceProp(Instance: TObject; const PropName: string; const Value: Pointer);
procedure SetRawInterfaceProp(Instance: TObject; PropInfo: TTypeMemberProperty; const Value: Pointer);
implementation
function GetTypeName(TypeInfo: TTypeInfo): string;
begin
Result := TypeInfo.Name;
end;
function GetClassMembers(aTIStruct: TTypeInfoStruct): TTypeMemberDynArray;
var
C: TTypeInfoStruct;
i: Integer;
PropName: String;
Names: TJSObject;
begin
Result:=nil;
Names:=TJSObject.new;
C:=aTIStruct;
while C<>nil do
begin
for i:=0 to length(C.Names)-1 do
begin
PropName:=C.Names[i];
if Names.hasOwnProperty(PropName) then continue;
TJSArray(Result).push(C.Members[PropName]);
Names[PropName]:=true;
end;
if not (C is TTypeInfoClass) then break;
C:=TTypeInfoClass(C).Ancestor;
end;
end;
function GetClassMember(aTIStruct: TTypeInfoStruct; const aName: String): TTypeMember;
var
C: TTypeInfoStruct;
i: Integer;
begin
// quick search: case sensitive
C:=aTIStruct;
while C<>nil do
begin
if TJSObject(C.Members).hasOwnProperty(aName) then
exit(C.Members[aName]);
if not (C is TTypeInfoClass) then break;
C:=TTypeInfoClass(C).Ancestor;
end;
// slow search: case insensitive
C:=aTIStruct;
while C<>nil do
begin
for i:=0 to length(C.Names)-1 do
if CompareText(C.Names[i],aName)=0 then
exit(C.Members[C.Names[i]]);
if not (C is TTypeInfoClass) then break;
C:=TTypeInfoClass(C).Ancestor;
end;
Result:=nil;
end;
function GetInstanceMethod(Instance: TObject; const aName: String): Pointer;
var
TI: TTypeMember;
begin
if Instance=nil then exit(nil);
TI:=GetClassMember(TypeInfo(Instance),aName);
if not (TI is TTypeMemberMethod) then exit(nil);
Result:=CreateMethod(Instance,TI.Name); // Note: use TI.Name for the correct case!
end;
function GetClassMethods(aTIStruct: TTypeInfoStruct): TTypeMemberMethodDynArray;
var
C: TTypeInfoStruct;
i, Cnt, j: Integer;
begin
Cnt:=0;
C:=aTIStruct;
while C<>nil do
begin
inc(Cnt,C.MethodCount);
if not (C is TTypeInfoClass) then break;
C:=TTypeInfoClass(C).Ancestor;
end;
SetLength(Result,Cnt);
C:=aTIStruct;
i:=0;
while C<>nil do
begin
for j:=0 to C.MethodCount-1 do
begin
Result[i]:=TTypeMemberMethod(C.Members[C.Methods[j]]);
inc(i);
end;
if not (C is TTypeInfoClass) then break;
C:=TTypeInfoClass(C).Ancestor;
end;
end;
function GetInterfaceMembers(aTIInterface: TTypeInfoInterface
): TTypeMemberDynArray;
var
Intf: TTypeInfoInterface;
i, Cnt, j: Integer;
begin
Cnt:=0;
Intf:=aTIInterface;
while Intf<>nil do
begin
inc(Cnt,length(Intf.Names));
Intf:=Intf.Ancestor;
end;
SetLength(Result,Cnt);
Intf:=aTIInterface;
i:=0;
while Intf<>nil do
begin
for j:=0 to length(Intf.Names)-1 do
begin
Result[i]:=Intf.Members[Intf.Names[j]];
inc(i);
end;
Intf:=Intf.Ancestor;
end;
end;
function GetInterfaceMember(aTIInterface: TTypeInfoInterface;
const aName: String): TTypeMember;
var
Intf: TTypeInfoInterface;
i: Integer;
begin
// quick search: case sensitive
Intf:=aTIInterface;
while Intf<>nil do
begin
if TJSObject(Intf.Members).hasOwnProperty(aName) then
exit(Intf.Members[aName]);
Intf:=Intf.Ancestor;
end;
// slow search: case insensitive
Intf:=aTIInterface;
while Intf<>nil do
begin
for i:=0 to length(Intf.Names)-1 do
if CompareText(Intf.Names[i],aName)=0 then
exit(Intf.Members[Intf.Names[i]]);
Intf:=Intf.Ancestor;
end;
Result:=nil;
end;
function GetInterfaceMethods(aTIInterface: TTypeInfoInterface
): TTypeMemberMethodDynArray;
var
Intf: TTypeInfoInterface;
i, Cnt, j: Integer;
begin
Cnt:=0;
Intf:=aTIInterface;
while Intf<>nil do
begin
inc(Cnt,Intf.MethodCount);
Intf:=Intf.Ancestor;
end;
SetLength(Result,Cnt);
Intf:=aTIInterface;
i:=0;
while Intf<>nil do
begin
for j:=0 to Intf.MethodCount-1 do
begin
Result[i]:=TTypeMemberMethod(Intf.Members[Intf.Methods[j]]);
inc(i);
end;
Intf:=Intf.Ancestor;
end;
end;
type
TCreatorAttribute = class external name 'attr'
class function Create(const ProcName: string): TCustomAttribute; overload; external name '$create';
class function Create(const ProcName: string; Params: jsvalue): TCustomAttribute; overload; external name '$create';
end;
TCreatorAttributeClass = class of TCreatorAttribute;
function GetRTTIAttributes(const Attributes: TTypeInfoAttributes
): TCustomAttributeArray;
var
i, len: Integer;
AttrClass: TCreatorAttributeClass;
ProcName: String;
Attr: TCustomAttribute;
begin
Result:=nil;
if Attributes=Undefined then exit;
i:=0;
len:=length(Attributes);
while i<len do
begin
AttrClass:=TCreatorAttributeClass(Attributes[i]);
inc(i);
ProcName:=String(Attributes[i]);
inc(i);
if (i<len) and isArray(Attributes[i]) then
begin
Attr:=AttrClass.Create(ProcName,Attributes[i]);
inc(i);
end
else
Attr:=AttrClass.Create(ProcName);
Insert(Attr,Result,length(Result));
end;
end;
function GetPropInfos(aTIStruct: TTypeInfoStruct): TTypeMemberPropertyDynArray;
var
C: TTypeInfoStruct;
i: Integer;
Names: TJSObject;
PropName: String;
begin
Result:=nil;
C:=aTIStruct;
Names:=TJSObject.new;
while C<>nil do
begin
for i:=0 to C.PropCount-1 do
begin
PropName:=C.Properties[i];
if Names.hasOwnProperty(PropName) then continue;
TJSArray(Result).push(TTypeMemberProperty(C.Members[PropName]));
Names[PropName]:=true;
end;
if not (C is TTypeInfoClass) then
break;
C:=TTypeInfoClass(C).Ancestor;
end;
end;
function GetPropList(aTIStruct: TTypeInfoStruct; TypeKinds: TTypeKinds;
Sorted: boolean): TTypeMemberPropertyDynArray;
function NameSort(a,b: JSValue): NativeInt;
begin
if TTypeMemberProperty(a).Name<TTypeMemberProperty(b).Name then
Result:=-1
else if TTypeMemberProperty(a).Name>TTypeMemberProperty(b).Name then
Result:=1
else
Result:=0;
end;
var
C: TTypeInfoStruct;
i: Integer;
Names: TJSObject;
PropName: String;
Prop: TTypeMemberProperty;
begin
Result:=nil;
C:=aTIStruct;
Names:=TJSObject.new;
while C<>nil do
begin
for i:=0 to C.PropCount-1 do
begin
PropName:=C.Properties[i];
if Names.hasOwnProperty(PropName) then continue;
Prop:=TTypeMemberProperty(C.Members[PropName]);
if not (Prop.TypeInfo.Kind in TypeKinds) then continue;
TJSArray(Result).push(Prop);
Names[PropName]:=true;
end;
if not (C is TTypeInfoClass) then
break;
C:=TTypeInfoClass(C).Ancestor;
end;
if Sorted then
TJSArray(Result).sort(@NameSort);
end;
function GetPropList(aTIStruct: TTypeInfoStruct): TTypeMemberPropertyDynArray;
begin
Result:=GetPropInfos(aTIStruct);
end;
function GetPropList(AClass: TClass): TTypeMemberPropertyDynArray;
begin
Result:=GetPropInfos(TypeInfo(AClass));
end;
function GetPropList(Instance: TObject): TTypeMemberPropertyDynArray;
begin
Result:=GetPropList(Instance.ClassType);
end;
function GetPropInfo(TI: TTypeInfoStruct; const PropName: String
): TTypeMemberProperty;
var
m: TTypeMember;
i: Integer;
C: TTypeInfoStruct;
begin
// quick search case sensitive
C:=TI;
while C<>nil do
begin
m:=C.Members[PropName];
if m is TTypeMemberProperty then
exit(TTypeMemberProperty(m));
if not (C is TTypeInfoClass) then
break;
C:=TTypeInfoClass(C).Ancestor;
end;
// slow search case insensitive
Result:=nil;
repeat
for i:=0 to TI.PropCount-1 do
if CompareText(PropName,TI.Properties[i])=0 then
begin
m:=TI.Members[TI.Properties[i]];
if m is TTypeMemberProperty then
Result:=TTypeMemberProperty(m);
exit;
end;
if not (TI is TTypeInfoClass) then
break;
TI:=TTypeInfoClass(TI).Ancestor;
until TI=nil;
end;
function GetPropInfo(TI: TTypeInfoStruct; const PropName: String;
const Kinds: TTypeKinds): TTypeMemberProperty;
begin
Result:=GetPropInfo(TI,PropName);
if (Kinds<>[]) and (Result<>nil) and not (Result.TypeInfo.Kind in Kinds) then
Result:=nil;
end;
function GetPropInfo(Instance: TObject; const PropName: String
): TTypeMemberProperty;
begin
Result:=GetPropInfo(TypeInfo(Instance),PropName,[]);
end;
function GetPropInfo(Instance: TObject; const PropName: String;
const Kinds: TTypeKinds): TTypeMemberProperty;
begin
Result:=GetPropInfo(TypeInfo(Instance),PropName,Kinds);
end;
function GetPropInfo(aClass: TClass; const PropName: String
): TTypeMemberProperty;
begin
Result:=GetPropInfo(TypeInfo(AClass),PropName,[]);
end;
function GetPropInfo(aClass: TClass; const PropName: String;
const Kinds: TTypeKinds): TTypeMemberProperty;
begin
Result:=GetPropInfo(TypeInfo(AClass),PropName,Kinds);
end;
function FindPropInfo(Instance: TObject; const PropName: String
): TTypeMemberProperty;
begin
Result:=GetPropInfo(TypeInfo(Instance), PropName);
if Result=nil then
raise EPropertyError.CreateFmt(SErrPropertyNotFound, [PropName]);
end;
function FindPropInfo(Instance: TObject; const PropName: String;
const Kinds: TTypeKinds): TTypeMemberProperty;
begin
Result:=GetPropInfo(TypeInfo(Instance), PropName, Kinds);
if Result=nil then
raise EPropertyError.CreateFmt(SErrPropertyNotFound, [PropName]);
end;
function FindPropInfo(aClass: TClass; const PropName: String
): TTypeMemberProperty;
begin
Result:=GetPropInfo(TypeInfo(aClass), PropName);
if Result=nil then
raise EPropertyError.CreateFmt(SErrPropertyNotFound, [PropName]);
end;
function FindPropInfo(aClass: TClass; const PropName: String;
const Kinds: TTypeKinds): TTypeMemberProperty;
begin
Result:=GetPropInfo(TypeInfo(aClass), PropName, Kinds);
if Result=nil then
raise EPropertyError.CreateFmt(SErrPropertyNotFound, [PropName]);
end;
function IsStoredProp(Instance: TObject; const PropInfo: TTypeMemberProperty
): Boolean;
type
TIsStored = function: Boolean of object;
begin
case PropInfo.Flags and 12 of
0: Result:=true;
4: Result:=false;
8: Result:=Boolean(TJSObject(Instance)[PropInfo.Stored]);
else Result:=TIsStored(TJSObject(Instance)[PropInfo.Stored])();
end;
end;
function IsStoredProp(Instance: TObject; const PropName: string): Boolean;
begin
Result:=IsStoredProp(Instance,FindPropInfo(Instance,PropName));
end;
function IsPublishedProp(Instance: TObject; const PropName: String): Boolean;
begin
Result:=GetPropInfo(Instance,PropName)<>nil;
end;
function IsPublishedProp(aClass: TClass; const PropName: String): Boolean;
begin
Result:=GetPropInfo(aClass,PropName)<>nil;
end;
function PropType(Instance: TObject; const PropName: string): TTypeKind;
begin
Result:=FindPropInfo(Instance,PropName).TypeInfo.Kind;
end;
function PropType(aClass: TClass; const PropName: string): TTypeKind;
begin
Result:=FindPropInfo(aClass,PropName).TypeInfo.Kind;
end;
function PropIsType(Instance: TObject; const PropName: string;
const TypeKind: TTypeKind): Boolean;
begin
Result:=PropType(Instance,PropName)=TypeKind;
end;
function PropIsType(aClass: TClass; const PropName: string;
const TypeKind: TTypeKind): Boolean;
begin
Result:=PropType(aClass,PropName)=TypeKind;
end;
type
TGetterKind = (
gkNone,
gkField,
gkFunction,
gkFunctionWithParams
);
function GetPropGetterKind(const PropInfo: TTypeMemberProperty): TGetterKind;
begin
if PropInfo.Getter='' then
Result:=gkNone
else if (pfGetFunction and PropInfo.Flags)>0 then
begin
if length(PropInfo.Params)>0 then
// array property
Result:=gkFunctionWithParams
else
Result:=gkFunction;
end
else
Result:=gkField;
end;
type
TSetterKind = (
skNone,
skField,
skProcedure,
skProcedureWithParams
);
function GetPropSetterKind(const PropInfo: TTypeMemberProperty): TSetterKind;
begin
if PropInfo.Setter='' then
Result:=skNone
else if (pfSetProcedure and PropInfo.Flags)>0 then
begin
if length(PropInfo.Params)>0 then
// array property
Result:=skProcedureWithParams
else
Result:=skProcedure;
end
else
Result:=skField;
end;
function GetJSValueProp(Instance: TJSObject; TI: TTypeInfoStruct;
const PropName: String): JSValue;
var
PropInfo: TTypeMemberProperty;
begin
PropInfo:=GetPropInfo(TI,PropName);
if PropInfo=nil then
raise EPropertyError.CreateFmt(SErrPropertyNotFound, [PropName]);
Result:=GetJSValueProp(Instance,PropInfo);
end;
function GetJSValueProp(Instance: TJSObject;
const PropInfo: TTypeMemberProperty): JSValue;
type
TGetter = function: JSValue of object;
TGetterWithIndex = function(Index: JSValue): JSValue of object;
var
gk: TGetterKind;
begin
gk:=GetPropGetterKind(PropInfo);
case gk of
gkNone:
raise EPropertyError.CreateFmt(SCantReadPropertyS, [PropInfo.Name]);
gkField:
Result:=Instance[PropInfo.Getter];
gkFunction:
if (pfHasIndex and PropInfo.Flags)>0 then
Result:=TGetterWithIndex(Instance[PropInfo.Getter])(PropInfo.Index)
else
Result:=TGetter(Instance[PropInfo.Getter])();
gkFunctionWithParams:
raise EPropertyError.CreateFmt(SIndexedPropertyNeedsParams, [PropInfo.Name]);
end;
end;
function GetJSValueProp(Instance: TObject; const PropName: String): JSValue;
begin
Result:=GetJSValueProp(Instance,FindPropInfo(Instance,PropName));
end;
function GetJSValueProp(Instance: TObject; const PropInfo: TTypeMemberProperty
): JSValue;
begin
Result:=GetJSValueProp(TJSObject(Instance),PropInfo);
end;
procedure SetJSValueProp(Instance: TJSObject; TI: TTypeInfoStruct;
const PropName: String; Value: JSValue);
var
PropInfo: TTypeMemberProperty;
begin
PropInfo:=GetPropInfo(TI,PropName);
if PropInfo=nil then
raise EPropertyError.CreateFmt(SErrPropertyNotFound, [PropName]);
SetJSValueProp(Instance,PropInfo,Value);
end;
procedure SetJSValueProp(Instance: TJSObject;
const PropInfo: TTypeMemberProperty; Value: JSValue);
type
TSetter = procedure(Value: JSValue) of object;
TSetterWithIndex = procedure(Index, Value: JSValue) of object;
var
sk: TSetterKind;
begin
sk:=GetPropSetterKind(PropInfo);
case sk of
skNone:
raise EPropertyError.CreateFmt(SCantWritePropertyS, [PropInfo.Name]);
skField:
Instance[PropInfo.Setter]:=Value;
skProcedure:
if (pfHasIndex and PropInfo.Flags)>0 then
TSetterWithIndex(Instance[PropInfo.Setter])(PropInfo.Index,Value)
else
TSetter(Instance[PropInfo.Setter])(Value);
skProcedureWithParams:
raise EPropertyError.CreateFmt(SIndexedPropertyNeedsParams, [PropInfo.Name]);
end;
end;
procedure SetJSValueProp(Instance: TObject; const PropName: String;
Value: JSValue);
begin
SetJSValueProp(Instance,FindPropInfo(Instance,PropName),Value);
end;
procedure SetJSValueProp(Instance: TObject;
const PropInfo: TTypeMemberProperty; Value: JSValue);
begin
SetJSValueProp(TJSObject(Instance),PropInfo,Value);
end;
function GetNativeIntProp(Instance: TObject; const PropName: String): NativeInt;
begin
Result:=GetNativeIntProp(Instance,FindPropInfo(Instance,PropName));
end;
function GetNativeIntProp(Instance: TObject; const PropInfo: TTypeMemberProperty
): NativeInt;
begin
Result:=NativeInt(GetJSValueProp(Instance,PropInfo));
end;
procedure SetNativeIntProp(Instance: TObject; const PropName: String;
Value: NativeInt);
begin
SetJSValueProp(Instance,FindPropInfo(Instance,PropName),Value);
end;
procedure SetNativeIntProp(Instance: TObject;
const PropInfo: TTypeMemberProperty; Value: NativeInt);
begin
SetJSValueProp(Instance,PropInfo,Value);
end;
function GetOrdProp(Instance: TObject; const PropName: String): longint;
begin
Result:=GetOrdProp(Instance,FindPropInfo(Instance,PropName));
end;
function GetOrdProp(Instance: TObject; const PropInfo: TTypeMemberProperty
): longint;
var
o: TJSObject;
Key: String;
n: NativeInt;
v : JSValue;
vs : TJSString absolute key;
begin
if PropInfo.TypeInfo.Kind=tkSet then
begin
// a set is a JS object, with the following property: o[ElementDecimal]=true
o:=TJSObject(GetJSValueProp(Instance,PropInfo));
Result:=0;
for Key in o do
begin
n:=parseInt(Key,10);
if n<32 then
Result:=Result+(1 shl n);
end;
end else if PropInfo.TypeInfo.Kind=tkChar then
begin
v:=GetJSValueProp(Instance,PropInfo);
if isNumber(v) then
Result:=Longint(V)
else
begin
Key:=String(v);
If Key='' then
Result:=0
else
Result:=vs.CharCodeAt(0);
end
end else
Result:=longint(GetJSValueProp(Instance,PropInfo));
end;
procedure SetOrdProp(Instance: TObject; const PropName: String; Value: longint);
begin
SetOrdProp(Instance,FindPropInfo(Instance,PropName),Value);
end;
procedure SetOrdProp(Instance: TObject; const PropInfo: TTypeMemberProperty;
Value: longint);
var
o: TJSObject;
i: Integer;
begin
if PropInfo.TypeInfo.Kind=tkSet then
begin
o:=TJSObject.new;
for i:=0 to 31 do
if (1 shl i) and Value>0 then
o[str(i)]:=true;
SetJSValueProp(Instance,PropInfo,o);
end else if PropInfo.TypeInfo.Kind=tkChar then
SetJSValueProp(Instance,PropInfo,TJSString.fromCharCode(Value))
else
SetJSValueProp(Instance,PropInfo,Value);
end;
function GetEnumProp(Instance: TObject; const PropName: String): String;
begin
Result:=GetEnumProp(Instance,FindPropInfo(Instance,PropName));
end;
function GetEnumProp(Instance: TObject; const PropInfo: TTypeMemberProperty): String;
var
n: NativeInt;
TIEnum: TTypeInfoEnum;
begin
TIEnum:=PropInfo.TypeInfo as TTypeInfoEnum;
n:=NativeInt(GetJSValueProp(Instance,PropInfo));
if (n>=TIEnum.MinValue) and (n<=TIEnum.MaxValue) then
Result:=TIEnum.EnumType.IntToName[n]
else
Result:=str(n);
end;
procedure SetEnumProp(Instance: TObject; const PropName: String;
const Value: String);
begin
SetEnumProp(Instance,FindPropInfo(Instance,PropName),Value);
end;
procedure SetEnumProp(Instance: TObject; const PropInfo: TTypeMemberProperty;
const Value: String);
var
TIEnum: TTypeInfoEnum;
n: NativeInt;
begin
TIEnum:=PropInfo.TypeInfo as TTypeInfoEnum;
n:=TIEnum.EnumType.NameToInt[Value];
if not isUndefined(n) then
SetJSValueProp(Instance,PropInfo,n);
end;
function GetEnumName(TypeInfo: TTypeInfoEnum; Value: Integer): String;
begin
Result:=TypeInfo.EnumType.IntToName[Value];
end;
function GetEnumValue(TypeInfo: TTypeInfoEnum; const Name: string): Longint;
begin
Result:=TypeInfo.EnumType.NameToInt[Name];
end;
function GetEnumNameCount(TypeInfo: TTypeInfoEnum): Longint;
var
o: TJSObject;
l, r: LongInt;
begin
o:=TJSObject(TypeInfo.EnumType);
// as of pas2js 1.0 the RTTI does not contain a min/max value
// -> use exponential search
// ToDo: adapt this once enums with gaps are supported
Result:=1;
while o.hasOwnProperty(String(JSValue(Result))) do
Result:=Result*2;
l:=Result div 2;
r:=Result;
while l<=r do
begin
Result:=(l+r) div 2;
if o.hasOwnProperty(String(JSValue(Result))) then
l:=Result+1
else
r:=Result-1;
end;
if o.hasOwnProperty(String(JSValue(Result))) then
inc(Result);
end;
function GetSetProp(Instance: TObject; const PropName: String): String;
begin
Result:=GetSetProp(Instance,FindPropInfo(Instance,PropName));
end;
function GetSetProp(Instance: TObject; const PropInfo: TTypeMemberProperty
): String;
var
o: TJSObject;
key, Value: String;
n: NativeInt;
TIEnum: TTypeInfoEnum;
TISet: TTypeInfoSet;
begin
Result:='';
// get enum type if available
TISet:=PropInfo.TypeInfo as TTypeInfoSet;
TIEnum:=nil;
if TISet.CompType is TTypeInfoEnum then
TIEnum:=TTypeInfoEnum(TISet.CompType);
// read value
o:=TJSObject(GetJSValueProp(Instance,PropInfo));
// a set is a JS object, where included element is stored as: o[ElementDecimal]=true
for Key in o do
begin
n:=parseInt(Key,10);
if (TIEnum<>nil) and (n>=TIEnum.MinValue) and (n<=TIEnum.MaxValue) then
Value:=TIEnum.EnumType.IntToName[n]
else
Value:=str(n);
if Result<>'' then Result:=Result+',';
Result:=Result+Value;
end;
Result:='['+Result+']';
end;
function GetSetPropArray(Instance: TObject; const PropName: String
): TIntegerDynArray;
begin
Result:=GetSetPropArray(Instance,FindPropInfo(Instance,PropName));
end;
function GetSetPropArray(Instance: TObject; const PropInfo: TTypeMemberProperty
): TIntegerDynArray;
var
o: TJSObject;
Key: string;
begin
Result:=[];
// read value
o:=TJSObject(GetJSValueProp(Instance,PropInfo));
// a set is a JS object, where included element is stored as: o[ElementDecimal]=true
for Key in o do
TJSArray(Result).push(parseInt(Key,10));
end;
procedure SetSetPropArray(Instance: TObject; const PropName: String;
const Arr: TIntegerDynArray);
begin
SetSetPropArray(Instance,FindPropInfo(Instance,PropName),Arr);
end;
procedure SetSetPropArray(Instance: TObject;
const PropInfo: TTypeMemberProperty; const Arr: TIntegerDynArray);
var
o: TJSObject;
i: integer;
begin
o:=TJSObject.new;
for i in Arr do
o[str(i)]:=true;
SetJSValueProp(Instance,PropInfo,o);
end;
function GetStrProp(Instance: TObject; const PropName: String): String;
begin
Result:=GetStrProp(Instance,FindPropInfo(Instance,PropName));
end;
function GetStrProp(Instance: TObject; const PropInfo: TTypeMemberProperty
): String;
begin
Result:=String(GetJSValueProp(Instance,PropInfo));
end;
procedure SetStrProp(Instance: TObject; const PropName: String; Value: String
);
begin
SetStrProp(Instance,FindPropInfo(Instance,PropName),Value);
end;
procedure SetStrProp(Instance: TObject; const PropInfo: TTypeMemberProperty;
Value: String);
begin
SetJSValueProp(Instance,PropInfo,Value);
end;
function GetStringProp(Instance: TObject; const PropName: String): String;
begin
Result:=GetStrProp(Instance,PropName);
end;
function GetStringProp(Instance: TObject; const PropInfo: TTypeMemberProperty
): String;
begin
Result:=GetStrProp(Instance,PropInfo);
end;
procedure SetStringProp(Instance: TObject; const PropName: String; Value: String
);
begin
SetStrProp(Instance,PropName,Value);
end;
procedure SetStringProp(Instance: TObject; const PropInfo: TTypeMemberProperty;
Value: String);
begin
SetStrProp(Instance,PropInfo,Value);
end;
function GetBoolProp(Instance: TObject; const PropName: String): boolean;
begin
Result:=GetBoolProp(Instance,FindPropInfo(Instance,PropName));
end;
function GetBoolProp(Instance: TObject; const PropInfo: TTypeMemberProperty
): boolean;
begin
Result:=Boolean(GetJSValueProp(Instance,PropInfo));
end;
procedure SetBoolProp(Instance: TObject; const PropName: String; Value: boolean
);
begin
SetBoolProp(Instance,FindPropInfo(Instance,PropName),Value);
end;
procedure SetBoolProp(Instance: TObject; const PropInfo: TTypeMemberProperty;
Value: boolean);
begin
SetJSValueProp(Instance,PropInfo,Value);
end;
function GetObjectProp(Instance: TObject; const PropName: String): TObject;
begin
Result:=GetObjectProp(Instance,FindPropInfo(Instance,PropName));
end;
function GetObjectProp(Instance: TObject; const PropName: String; MinClass : TClass): TObject;
begin
Result:=GetObjectProp(Instance,FindPropInfo(Instance,PropName));
if (MinClass<>Nil) and (Result<>Nil) Then
if not Result.InheritsFrom(MinClass) then
Result:=Nil;
end;
function GetObjectProp(Instance: TObject; const PropInfo: TTypeMemberProperty): TObject;
begin
Result:=GetObjectProp(Instance,PropInfo,Nil);
end;
function GetObjectProp(Instance: TObject; const PropInfo: TTypeMemberProperty; MinClass : TClass): TObject;
Var
O : TObject;
begin
O:=TObject(GetJSValueProp(Instance,PropInfo));
if (MinClass<>Nil) and not O.InheritsFrom(MinClass) then
Result:=Nil
else
Result:=O;
end;
procedure SetObjectProp(Instance: TObject; const PropName: String; Value: TObject) ;
begin
SetObjectProp(Instance,FindPropInfo(Instance,PropName),Value);
end;
procedure SetObjectProp(Instance: TObject; const PropInfo: TTypeMemberProperty; Value: TObject);
begin
SetJSValueProp(Instance,PropInfo,Value);
end;
function GetMethodProp(Instance: TObject; PropInfo: TTypeMemberProperty
): TMethod;
var
v, fn: JSValue;
begin
Result.Code:=nil;
Result.Data:=nil;
v:=GetJSValueProp(Instance,PropInfo);
if not isFunction(v) then exit;
Result.Data:=Pointer(TJSObject(v)['scope']);
fn:=TJSObject(v)['fn'];
if isString(fn) then
begin
if Result.Data<>nil then
// named callback
Result.Code:=CodePointer(TJSObject(Result.Data)[String(fn)])
else
// this is not an rtl callback, return the value
Result.Code:=CodePointer(v);
end
else
// anonymous callback
Result.Code:=CodePointer(fn);
end;
function GetMethodProp(Instance: TObject; const PropName: string): TMethod;
begin
Result:=GetMethodProp(Instance,FindPropInfo(Instance,PropName));
end;
function createCallbackPtr(scope: Pointer; fn: CodePointer): TJSFunction; external name 'rtl.createCallback';
function createCallbackStr(scope: Pointer; fn: string): TJSFunction; external name 'rtl.createCallback';
procedure SetMethodProp(Instance: TObject; PropInfo: TTypeMemberProperty;
const Value: TMethod);
var
cb: TJSFunction;
Code: Pointer;
begin
// Note: Value.Data=nil is allowed and can be used by designer code
Code:=Value.Code;
if Code=nil then
cb:=nil
else if isFunction(Code) then
begin
if (TJSObject(Code)['scope']=Value.Data)
and (isFunction(TJSObject(Code)['fn']) or isString(TJSObject(Code)['fn']))
then
begin
// Value.Code is already the needed callback
cb:=TJSFunction(Code);
end
else if isString(TJSObject(Code)['fn']) then
// named callback, different scope
cb:=createCallbackStr(Value.Data,string(TJSObject(Code)['fn']))
else
// normal function
cb:=createCallbackPtr(Value.Data,Code);
end
else
// not a valid value -> for compatibility set it anyway
cb:=createCallbackPtr(Value.Data,Code);
SetJSValueProp(Instance,PropInfo,cb);
end;
procedure SetMethodProp(Instance: TObject; const PropName: string;
const Value: TMethod);
begin
SetMethodProp(Instance,FindPropInfo(Instance,PropName),Value);
end;
function GetInterfaceProp(Instance: TObject; const PropName: string
): IInterface;
begin
Result:=GetInterfaceProp(Instance,FindPropInfo(Instance,PropName));
end;
function GetInterfaceProp(Instance: TObject; PropInfo: TTypeMemberProperty
): IInterface;
type
TGetter = function: IInterface of object;
TGetterWithIndex = function(Index: JSValue): IInterface of object;
var
gk: TGetterKind;
begin
if Propinfo.TypeInfo.Kind<>tkInterface then
raise Exception.Create('Cannot get RAW interface from IInterface interface');
gk:=GetPropGetterKind(PropInfo);
case gk of
gkNone:
raise EPropertyError.CreateFmt(SCantReadPropertyS, [PropInfo.Name]);
gkField:
Result:=IInterface(TJSObject(Instance)[PropInfo.Getter]);
gkFunction:
if (pfHasIndex and PropInfo.Flags)>0 then
Result:=TGetterWithIndex(TJSObject(Instance)[PropInfo.Getter])(PropInfo.Index)
else
Result:=TGetter(TJSObject(Instance)[PropInfo.Getter])();
gkFunctionWithParams:
raise EPropertyError.CreateFmt(SIndexedPropertyNeedsParams, [PropInfo.Name]);
end;
end;
procedure SetInterfaceProp(Instance: TObject; const PropName: string;
const Value: IInterface);
begin
SetInterfaceProp(Instance,FindPropInfo(Instance,PropName),Value);
end;
procedure SetInterfaceProp(Instance: TObject; PropInfo: TTypeMemberProperty;
const Value: IInterface);
type
TSetter = procedure(Value: IInterface) of object;
TSetterWithIndex = procedure(Index: JSValue; Value: IInterface) of object;
procedure setIntfP(Instance: TObject; const PropName: string; value: jsvalue); external name 'rtl.setIntfP';
var
sk: TSetterKind;
Setter: String;
begin
if Propinfo.TypeInfo.Kind<>tkInterface then
raise Exception.Create('Cannot set RAW interface from IInterface interface');
sk:=GetPropSetterKind(PropInfo);
Setter:=PropInfo.Setter;
case sk of
skNone:
raise EPropertyError.CreateFmt(SCantWritePropertyS, [PropInfo.Name]);
skField:
setIntfP(Instance,Setter,Value);
skProcedure:
if (pfHasIndex and PropInfo.Flags)>0 then
TSetterWithIndex(TJSObject(Instance)[Setter])(PropInfo.Index,Value)
else
TSetter(TJSObject(Instance)[Setter])(Value);
skProcedureWithParams:
raise EPropertyError.CreateFmt(SIndexedPropertyNeedsParams, [PropInfo.Name]);
end;
end;
function GetRawInterfaceProp(Instance: TObject; const PropName: string
): Pointer;
begin
Result:=GetRawInterfaceProp(Instance,FindPropInfo(Instance,PropName));
end;
function GetRawInterfaceProp(Instance: TObject; PropInfo: TTypeMemberProperty
): Pointer;
begin
Result:=Pointer(GetJSValueProp(Instance,PropInfo));
end;
procedure SetRawInterfaceProp(Instance: TObject; const PropName: string;
const Value: Pointer);
begin
SetRawInterfaceProp(Instance,FindPropInfo(Instance,PropName),Value);
end;
procedure SetRawInterfaceProp(Instance: TObject; PropInfo: TTypeMemberProperty;
const Value: Pointer);
begin
SetJSValueProp(Instance,PropInfo,Value);
end;
function GetFloatProp(Instance: TObject; PropInfo: TTypeMemberProperty): Double;
begin
Result:=Double(GetJSValueProp(Instance,PropInfo));
end;
function GetFloatProp(Instance: TObject; const PropName: string): Double;
begin
Result:=GetFloatProp(Instance,FindPropInfo(Instance,PropName));
end;
procedure SetFloatProp(Instance: TObject; const PropName: string; Value: Double
);
begin
SetFloatProp(Instance,FindPropInfo(Instance,PropName),Value);
end;
procedure SetFloatProp(Instance: TObject; PropInfo: TTypeMemberProperty;
Value: Double);
begin
SetJSValueProp(Instance,PropInfo,Value);
end;
end.