Static specialization WIP
This commit is contained in:
+225
-54
@@ -39,6 +39,7 @@ type
|
||||
{$endregion}
|
||||
property ParamTypes: TArray<IStaticType> read GetParamTypes;
|
||||
property ReturnType: IStaticType read GetReturnType;
|
||||
function GetHashCode: Integer;
|
||||
end;
|
||||
|
||||
// Defines a mapping for generic record fields (Key -> StaticType)
|
||||
@@ -50,7 +51,8 @@ type
|
||||
{$region 'private'}
|
||||
function GetKind: TStaticTypeKind;
|
||||
function GetElementType: IStaticType;
|
||||
function GetSignature: IMethodSignature;
|
||||
// function GetSignature: IMethodSignature; // (* REMOVED *)
|
||||
function GetSignatures: TArray<IMethodSignature>; // (* ADDED *)
|
||||
function GetDefinition: IScalarRecordDefinition;
|
||||
function GetGenericDefinition: IGenericRecordDefinition;
|
||||
{$endregion}
|
||||
@@ -59,8 +61,12 @@ type
|
||||
property Kind: TStaticTypeKind read GetKind;
|
||||
// The element type (if Kind = stSeries)
|
||||
property ElementType: IStaticType read GetElementType;
|
||||
// The signature (if Kind = stMethod)
|
||||
property Signature: IMethodSignature read GetSignature;
|
||||
|
||||
// The signatures (if Kind = stMethod).
|
||||
// This array contains one entry for simple methods,
|
||||
// and multiple entries for overloaded functions (like RTL).
|
||||
property Signatures: TArray<IMethodSignature> read GetSignatures;
|
||||
|
||||
// The definition (if Kind = stRecord or stRecordSeries)
|
||||
property Definition: IScalarRecordDefinition read GetDefinition;
|
||||
// The definition (if Kind = stGenericRecord)
|
||||
@@ -69,6 +75,7 @@ type
|
||||
// Checks for type equality
|
||||
function IsEqual(const Other: IStaticType): Boolean;
|
||||
function ToString: string;
|
||||
function GetHashCode: Integer;
|
||||
end;
|
||||
|
||||
ETypeException = class(Exception);
|
||||
@@ -102,6 +109,7 @@ type
|
||||
// Factory functions for complex types
|
||||
class function CreateSeries(const AElementType: IStaticType): IStaticType; static;
|
||||
class function CreateMethod(const AParamTypes: TArray<IStaticType>; const AReturnType: IStaticType): IStaticType; static;
|
||||
class function CreateMethodSet(const ASignatures: TArray<IMethodSignature>): IStaticType; static;
|
||||
class function CreateRecord(const ADef: IScalarRecordDefinition): IStaticType; static;
|
||||
class function CreateRecordSeries(const ADef: IScalarRecordDefinition): IStaticType; static;
|
||||
class function CreateGenericRecord(const ADef: IGenericRecordDefinition): IStaticType; static;
|
||||
@@ -123,10 +131,22 @@ type
|
||||
class function ResolveUnaryOp(Op: TScalar.TUnaryOp; const Right: IStaticType): IStaticType; static;
|
||||
end;
|
||||
|
||||
TMethodSignature = class(TInterfacedObject, IMethodSignature)
|
||||
private
|
||||
FParamTypes: TArray<IStaticType>;
|
||||
FReturnType: IStaticType;
|
||||
function GetParamTypes: TArray<IStaticType>;
|
||||
function GetReturnType: IStaticType;
|
||||
public
|
||||
constructor Create(const AParamTypes: TArray<IStaticType>; const AReturnType: IStaticType);
|
||||
function GetHashCode: Integer; override;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
System.Generics.Defaults;
|
||||
System.Generics.Defaults,
|
||||
System.Hash; // Added for TStringBuilder in TMethodType.ToString
|
||||
|
||||
{ TStaticTypeKindHelper }
|
||||
|
||||
@@ -157,10 +177,11 @@ type
|
||||
// IStaticType (default implementations for non-applicable properties)
|
||||
function GetKind: TStaticTypeKind; virtual; abstract;
|
||||
function GetElementType: IStaticType; virtual;
|
||||
function GetSignature: IMethodSignature; virtual;
|
||||
function GetSignatures: TArray<IMethodSignature>; virtual; // (* CHANGED *)
|
||||
function GetDefinition: IScalarRecordDefinition; virtual;
|
||||
function GetGenericDefinition: IGenericRecordDefinition; virtual;
|
||||
function IsEqual(const Other: IStaticType): Boolean; virtual;
|
||||
function GetHashCode: Integer; override; abstract;
|
||||
function ToString: string; override;
|
||||
end;
|
||||
|
||||
@@ -169,9 +190,9 @@ begin
|
||||
Result := nil;
|
||||
end;
|
||||
|
||||
function TAbstractStaticType.GetSignature: IMethodSignature;
|
||||
function TAbstractStaticType.GetSignatures: TArray<IMethodSignature>; // (* CHANGED *)
|
||||
begin
|
||||
Result := nil;
|
||||
Result := nil; // (* CHANGED *)
|
||||
end;
|
||||
|
||||
function TAbstractStaticType.GetDefinition: IScalarRecordDefinition;
|
||||
@@ -208,6 +229,7 @@ type
|
||||
public
|
||||
constructor Create(AKind: TStaticTypeKind);
|
||||
function GetKind: TStaticTypeKind; override;
|
||||
function GetHashCode: Integer; override;
|
||||
end;
|
||||
|
||||
constructor TSimpleStaticType.Create(AKind: TStaticTypeKind);
|
||||
@@ -221,6 +243,12 @@ begin
|
||||
Result := FKind;
|
||||
end;
|
||||
|
||||
function TSimpleStaticType.GetHashCode: Integer;
|
||||
begin
|
||||
// Simple types only hash their kind
|
||||
Result := Ord(FKind);
|
||||
end;
|
||||
|
||||
// --- Complex Type Implementations ---
|
||||
|
||||
type
|
||||
@@ -232,6 +260,7 @@ type
|
||||
function GetKind: TStaticTypeKind; override;
|
||||
function GetElementType: IStaticType; override;
|
||||
function IsEqual(const Other: IStaticType): Boolean; override;
|
||||
function GetHashCode: Integer; override;
|
||||
function ToString: string; override;
|
||||
end;
|
||||
|
||||
@@ -256,22 +285,24 @@ begin
|
||||
Result := (Assigned(Other)) and (Other.Kind = stSeries) and (Self.FElementType.IsEqual(Other.ElementType));
|
||||
end;
|
||||
|
||||
function TSeriesType.GetHashCode: Integer;
|
||||
begin
|
||||
// Consistent with IsEqual
|
||||
Result := Ord(stSeries);
|
||||
if Assigned(FElementType) then
|
||||
begin
|
||||
// Combine hash of stSeries with hash of element type
|
||||
var hash := FElementType.GetHashCode;
|
||||
Result := THashBobJenkins.GetHashValue(Hash, SizeOf(Integer), Result);
|
||||
end;
|
||||
end;
|
||||
|
||||
function TSeriesType.ToString: string;
|
||||
begin
|
||||
Result := 'Series<' + FElementType.ToString + '>';
|
||||
end;
|
||||
|
||||
// ---
|
||||
type
|
||||
TMethodSignature = class(TInterfacedObject, IMethodSignature)
|
||||
private
|
||||
FParamTypes: TArray<IStaticType>;
|
||||
FReturnType: IStaticType;
|
||||
function GetParamTypes: TArray<IStaticType>;
|
||||
function GetReturnType: IStaticType;
|
||||
public
|
||||
constructor Create(const AParamTypes: TArray<IStaticType>; const AReturnType: IStaticType);
|
||||
end;
|
||||
{ TMethodSignature }
|
||||
|
||||
constructor TMethodSignature.Create(const AParamTypes: TArray<IStaticType>; const AReturnType: IStaticType);
|
||||
begin
|
||||
@@ -290,23 +321,46 @@ begin
|
||||
Result := FReturnType;
|
||||
end;
|
||||
|
||||
function TMethodSignature.GetHashCode: Integer;
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
// Consistent with TMethodType.IsEqual
|
||||
Result := 0;
|
||||
if Assigned(FReturnType) then
|
||||
Result := FReturnType.GetHashCode;
|
||||
|
||||
for i := 0 to High(FParamTypes) do
|
||||
begin
|
||||
if Assigned(FParamTypes[i]) then
|
||||
begin
|
||||
var hash := FParamTypes[i].GetHashCode;
|
||||
Result := THashBobJenkins.GetHashValue(hash, SizeOf(Integer), Result);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
// ---
|
||||
type
|
||||
// (* ENTIRE TMethodType IMPLEMENTATION REPLACED *)
|
||||
TMethodType = class(TAbstractStaticType)
|
||||
private
|
||||
FSignature: IMethodSignature;
|
||||
FSignatures: TArray<IMethodSignature>;
|
||||
function SignatureToString(const Sig: IMethodSignature): string;
|
||||
public
|
||||
constructor Create(AParamTypes: TArray<IStaticType>; AReturnType: IStaticType);
|
||||
constructor Create(const ASignatures: TArray<IMethodSignature>);
|
||||
function GetKind: TStaticTypeKind; override;
|
||||
function GetSignature: IMethodSignature; override;
|
||||
function GetSignatures: TArray<IMethodSignature>; override;
|
||||
function IsEqual(const Other: IStaticType): Boolean; override;
|
||||
function GetHashCode: Integer; override;
|
||||
function ToString: string; override;
|
||||
end;
|
||||
|
||||
constructor TMethodType.Create(AParamTypes: TArray<IStaticType>; AReturnType: IStaticType);
|
||||
constructor TMethodType.Create(const ASignatures: TArray<IMethodSignature>);
|
||||
begin
|
||||
inherited Create;
|
||||
FSignature := TMethodSignature.Create(AParamTypes, AReturnType);
|
||||
Assert(Length(ASignatures) > 0, 'Cannot create a method type with zero signatures');
|
||||
FSignatures := ASignatures;
|
||||
end;
|
||||
|
||||
function TMethodType.GetKind: TStaticTypeKind;
|
||||
@@ -314,47 +368,106 @@ begin
|
||||
Result := stMethod;
|
||||
end;
|
||||
|
||||
function TMethodType.GetSignature: IMethodSignature;
|
||||
function TMethodType.GetSignatures: TArray<IMethodSignature>;
|
||||
begin
|
||||
Result := FSignature;
|
||||
Result := FSignatures;
|
||||
end;
|
||||
|
||||
function TMethodType.IsEqual(const Other: IStaticType): Boolean;
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
if (not Assigned(Other)) or (Other.Kind <> stMethod) then
|
||||
exit(False);
|
||||
|
||||
var otherSig := Other.Signature;
|
||||
if not Self.FSignature.ReturnType.IsEqual(otherSig.ReturnType) then
|
||||
exit(False);
|
||||
|
||||
if Length(Self.FSignature.ParamTypes) <> Length(otherSig.ParamTypes) then
|
||||
exit(False);
|
||||
|
||||
for i := 0 to High(Self.FSignature.ParamTypes) do
|
||||
begin
|
||||
if not Self.FSignature.ParamTypes[i].IsEqual(otherSig.ParamTypes[i]) then
|
||||
exit(False);
|
||||
end;
|
||||
|
||||
Result := True;
|
||||
end;
|
||||
|
||||
function TMethodType.ToString: string;
|
||||
function TMethodType.SignatureToString(const Sig: IMethodSignature): string;
|
||||
var
|
||||
i: Integer;
|
||||
paramStr: string;
|
||||
begin
|
||||
paramStr := '';
|
||||
for i := 0 to High(FSignature.ParamTypes) do
|
||||
for i := 0 to High(Sig.ParamTypes) do
|
||||
begin
|
||||
paramStr := paramStr + FSignature.ParamTypes[i].ToString;
|
||||
if i < High(FSignature.ParamTypes) then
|
||||
paramStr := paramStr + Sig.ParamTypes[i].ToString;
|
||||
if i < High(Sig.ParamTypes) then
|
||||
paramStr := paramStr + ', ';
|
||||
end;
|
||||
Result := Format('Method(%s): %s', [paramStr, FSignature.ReturnType.ToString]);
|
||||
Result := Format('Method(%s): %s', [paramStr, Sig.ReturnType.ToString]);
|
||||
end;
|
||||
|
||||
function TMethodType.IsEqual(const Other: IStaticType): Boolean;
|
||||
var
|
||||
i, j: Integer;
|
||||
begin
|
||||
if (not Assigned(Other)) or (Other.Kind <> stMethod) then
|
||||
exit(False);
|
||||
|
||||
var otherSigs := Other.Signatures;
|
||||
if Length(Self.FSignatures) <> Length(otherSigs) then
|
||||
exit(False);
|
||||
|
||||
// This is complex. For now, assume equality means identical sets,
|
||||
// which requires comparing O(N^2) signatures if order doesn't matter.
|
||||
// Let's assume order *does* matter for equality to keep this simple (O(N)).
|
||||
// Note: A better IsEqual would compare hashes of signatures.
|
||||
|
||||
for i := 0 to High(Self.FSignatures) do
|
||||
begin
|
||||
var sig1 := Self.FSignatures[i];
|
||||
var sig2 := otherSigs[i];
|
||||
|
||||
if not sig1.ReturnType.IsEqual(sig2.ReturnType) then
|
||||
exit(False);
|
||||
if Length(sig1.ParamTypes) <> Length(sig2.ParamTypes) then
|
||||
exit(False);
|
||||
|
||||
for j := 0 to High(sig1.ParamTypes) do
|
||||
begin
|
||||
if not sig1.ParamTypes[j].IsEqual(sig2.ParamTypes[j]) then
|
||||
exit(False);
|
||||
end;
|
||||
end;
|
||||
|
||||
Result := True;
|
||||
end;
|
||||
|
||||
function TMethodType.GetHashCode: Integer;
|
||||
var
|
||||
sig: IMethodSignature;
|
||||
begin
|
||||
// Consistent with IsEqual
|
||||
Result := Ord(stMethod);
|
||||
for sig in FSignatures do
|
||||
begin
|
||||
if Assigned(sig) then
|
||||
begin
|
||||
var hash := sig.GetHashCode;
|
||||
Result := THashBobJenkins.GetHashValue(hash, SizeOf(Integer), Result);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TMethodType.ToString: string;
|
||||
var
|
||||
sb: TStringBuilder;
|
||||
sig: IMethodSignature;
|
||||
begin
|
||||
if Length(FSignatures) = 1 then
|
||||
begin
|
||||
Result := SignatureToString(FSignatures[0]);
|
||||
end
|
||||
else
|
||||
begin
|
||||
// Handle overloaded methods
|
||||
sb := TStringBuilder.Create;
|
||||
try
|
||||
sb.Append('Method{');
|
||||
for sig in FSignatures do
|
||||
begin
|
||||
sb.Append('(');
|
||||
sb.Append(SignatureToString(sig));
|
||||
sb.Append('), ');
|
||||
end;
|
||||
sb.Remove(sb.Length - 2, 2); // Remove last ', '
|
||||
sb.Append('}');
|
||||
Result := sb.ToString;
|
||||
finally
|
||||
sb.Free;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
// ---
|
||||
@@ -369,6 +482,7 @@ type
|
||||
function GetKind: TStaticTypeKind; override;
|
||||
function GetDefinition: IScalarRecordDefinition; override;
|
||||
function IsEqual(const Other: IStaticType): Boolean; override;
|
||||
function GetHashCode: Integer; override; // Added
|
||||
function ToString: string; override;
|
||||
end;
|
||||
|
||||
@@ -414,6 +528,26 @@ begin
|
||||
Result := True;
|
||||
end;
|
||||
|
||||
function TRecordType.GetHashCode: Integer;
|
||||
var
|
||||
field: TPair<IKeyword, TScalar.TKind>;
|
||||
begin
|
||||
// Consistent with IsEqual
|
||||
Result := Ord(GetKind);
|
||||
if Assigned(FDefinition) then
|
||||
begin
|
||||
for field in FDefinition.Fields do
|
||||
begin
|
||||
// Hash the Keyword pointer (fast, from flyweight)
|
||||
var hash := TEqualityComparer<IKeyword>.Default.GetHashCode(field.Key);
|
||||
Result := THashBobJenkins.GetHashValue(hash, SizeOf(Pointer), Result);
|
||||
// Hash the TScalar.TKind value
|
||||
var data := Ord(field.Value);
|
||||
Result := THashBobJenkins.GetHashValue(data, SizeOf(Byte), Result);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TRecordType.ToString: string;
|
||||
var
|
||||
i: Integer;
|
||||
@@ -441,6 +575,7 @@ type
|
||||
function GetKind: TStaticTypeKind; override;
|
||||
function GetGenericDefinition: IGenericRecordDefinition; override;
|
||||
function IsEqual(const Other: IStaticType): Boolean; override;
|
||||
function GetHashCode: Integer; override; // Added
|
||||
function ToString: string; override;
|
||||
end;
|
||||
|
||||
@@ -485,6 +620,29 @@ begin
|
||||
Result := True;
|
||||
end;
|
||||
|
||||
function TGenericRecordType.GetHashCode: Integer;
|
||||
var
|
||||
field: TPair<IKeyword, IStaticType>;
|
||||
begin
|
||||
// Consistent with IsEqual
|
||||
Result := Ord(stGenericRecord);
|
||||
if Assigned(FDefinition) then
|
||||
begin
|
||||
for field in FDefinition.Fields do
|
||||
begin
|
||||
// Hash the Keyword pointer (fast, from flyweight)
|
||||
var data := TEqualityComparer<IKeyword>.Default.GetHashCode(field.Key);
|
||||
Result := THashBobJenkins.GetHashValue(data, SizeOf(Pointer), Result);
|
||||
// Hash the IStaticType value
|
||||
if Assigned(field.Value) then
|
||||
begin
|
||||
var hash := field.Value.GetHashCode;
|
||||
Result := THashBobJenkins.GetHashValue(hash, SizeOf(Integer), Result);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TGenericRecordType.ToString: string;
|
||||
var
|
||||
i: Integer;
|
||||
@@ -516,8 +674,21 @@ begin
|
||||
end;
|
||||
|
||||
class function TTypes.CreateMethod(const AParamTypes: TArray<IStaticType>; const AReturnType: IStaticType): IStaticType;
|
||||
var
|
||||
sig: IMethodSignature;
|
||||
sigs: TArray<IMethodSignature>;
|
||||
begin
|
||||
Result := TMethodType.Create(AParamTypes, AReturnType);
|
||||
// This is now a convenience helper for CreateMethodSet
|
||||
sig := TMethodSignature.Create(AParamTypes, AReturnType);
|
||||
SetLength(sigs, 1);
|
||||
sigs[0] := sig;
|
||||
Result := TMethodType.Create(sigs);
|
||||
end;
|
||||
|
||||
class function TTypes.CreateMethodSet(const ASignatures: TArray<IMethodSignature>): IStaticType;
|
||||
begin
|
||||
// This is the new primary factory for method types
|
||||
Result := TMethodType.Create(ASignatures);
|
||||
end;
|
||||
|
||||
class function TTypes.CreateRecord(const ADef: IScalarRecordDefinition): IStaticType;
|
||||
|
||||
Reference in New Issue
Block a user