Static specialization WIP

This commit is contained in:
Michael Schimmel
2025-11-19 14:38:40 +01:00
parent c129c1a3ae
commit 138e7ac454
26 changed files with 2349 additions and 1110 deletions
+225 -54
View File
@@ -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;