paxCompiler/Sources/PAXCOMP_MAP.pas
Dalibor Marković 9d0de424e8
Init
Signed-off-by: Dalibor Marković <dalibor31@gmail.com>
2024-07-06 22:28:12 +02:00

890 lines
20 KiB
ObjectPascal

////////////////////////////////////////////////////////////////////////////
// PaxCompiler
// Site: http://www.paxcompiler.com
// Author: Alexander Baranovsky (paxscript@gmail.com)
// ========================================================================
// Copyright (c) Alexander Baranovsky, 2006-2014. All rights reserved.
// Code Version: 4.2
// ========================================================================
// Unit: PAXCOMP_MAP.pas
// ========================================================================
////////////////////////////////////////////////////////////////////////////
{$I PaxCompiler.def}
unit PAXCOMP_MAP;
interface
uses {$I uses.def}
SysUtils,
Classes,
PAXCOMP_CONSTANTS,
PAXCOMP_TYPES,
PAXCOMP_SYS,
PAXCOMP_OFFSET;
type
TMapFieldRec = class
public
FieldName: String;
FieldOffset: Integer;
{$IFDEF PCU_EX}
FieldTypeName: String;
{$ENDIF}
procedure SaveToStream(S: TStream);
procedure LoadFromStream(S: TStream);
end;
TMapFieldList = class(TTypedList)
private
function GetRecord(I: Integer): TMapFieldRec;
public
function Add(const FieldName: String;
FieldOffset: Integer;
const FieldTypeName: String): TMapFieldRec;
procedure SaveToStream(S: TStream);
procedure LoadFromStream(S: TStream);
function Lookup(const FieldName: String): TMapFieldRec;
property Records[I: Integer]: TMapFieldRec read GetRecord; default;
end;
TSubParamRec = class
public
FinTypeId: Byte;
ParamMod: Byte;
ParamSize: Integer;
// pcu only
ParamName: String;
ParamTypeName: String;
OptValue: String;
ParamOffset: Integer;
end;
TSubParamList = class(TTypedList)
private
function GetRecord(I: Integer): TSubParamRec;
public
function IndexOf(const AName: String): Integer;
function AddRecord: TSubParamRec;
procedure SaveToStream(S: TStream);
procedure LoadFromStream(S: TStream);
property Records[I: Integer]: TSubParamRec read GetRecord; default;
end;
TSubLocalVarRec = class
public
LocalVarName: String;
LocalVarTypeName: String;
LocalVarOffset: Integer;
IsByRef: Boolean;
end;
TSubLocalVarList = class(TTypedList)
private
function GetRecord(I: Integer): TSubLocalVarRec;
public
function IndexOf(const AName: String): Integer;
function AddRecord: TSubLocalVarRec;
procedure SaveToStream(S: TStream);
procedure LoadFromStream(S: TStream);
property Records[I: Integer]: TSubLocalVarRec
read GetRecord; default;
end;
TSubDesc = class
public
OverCount: Byte;
CallConv: Byte;
CallMode: Byte;
ResTypeId: Byte;
MethodIndex: Integer;
RetSize: Integer;
ParamList: TSubParamList;
// pcu only
LocalVarList: TSubLocalVarList;
ResTypeName: String;
IsMethod: Boolean;
IsShared: Boolean;
SubName: String;
DllName: String;
AliasName: String;
SId: Integer;
N1: Integer;
N2: Integer;
SelfOffset: Integer;
SubSize: Integer; // not save to stream
constructor Create;
destructor Destroy; override;
procedure SaveToStream(S: TStream);
procedure LoadFromStream(S: TStream);
end;
TSubDescList = class(TTypedList)
private
function GetRecord(I: Integer): TSubDesc;
public
function AddRecord: TSubDesc;
procedure SaveToStream(S: TStream);
procedure LoadFromStream(S: TStream);
property Records[I: Integer]: TSubDesc read GetRecord; default;
end;
TMapRec = class
private
function GetIsMethod: Boolean;
public
FullName: String;
Shift: Integer;
Offset: Integer;
ClassIndex: Integer;
Kind: Byte;
Global: Boolean;
Vis: TClassVisibility;
TypedConst: Boolean;
FullTypeName: String;
IsExternal: Boolean;
SubDesc: TSubDesc;
FieldList: TMapFieldList;
constructor Create;
destructor Destroy; override;
procedure SaveToStream(S: TStream);
procedure LoadFromStream(S: TStream);
property IsMethod: Boolean read GetIsMethod;
end;
TMapTable = class(TTypedList)
private
function GetRecord(I: Integer): TMapRec;
function Add: TMapRec;
public
function AddRec(const FullName: String;
Shift: Integer;
ClassIndex: Integer;
Kind: Byte;
Global: Boolean;
OverCount: Byte;
CallMode: Byte): TMapRec;
function LookupByOffset(Offset: Integer): TMapRec;
function Lookup(const FullName: String): TMapRec;
function LookupEx(const FullName: String; OverCount: Integer): TMapRec;
function LookupType(const FullName: String): TMapRec;
function LookupConstructor(const AClassName: String; NP: Integer): TMapRec;
function LookupSub(SubId: Integer): TMapRec;
function GetSub(N: Integer): TMapRec;
procedure SaveToStream(S: TStream);
procedure LoadFromStream(S: TStream);
procedure CreateOffsets(OffsetList: TOffsetList; Host: Boolean);
property Records[I: Integer]: TMapRec read GetRecord; default;
end;
TTypeMapRec = class
public
TypeId: Integer;
Fields: TIntegerList;
Completed: Boolean;
constructor Create;
destructor Destroy; override;
end;
TTypeMap = class(TTypedList)
private
function GetRecord(I: Integer): TTypeMapRec;
public
function Add(TypeId: Integer): TTypeMapRec;
function Lookup(TypeId: Integer): TTypeMapRec;
property Records[I: Integer]: TTypeMapRec read GetRecord; default;
end;
implementation
// TSubLocalVarList ------------------------------------------------------------
function TSubLocalVarList.GetRecord(I: Integer): TSubLocalVarRec;
begin
result := TSubLocalVarRec(L[I]);
end;
function TSubLocalVarList.IndexOf(const AName: String): Integer;
var
I: Integer;
begin
result := -1;
for I := 0 to Count - 1 do
if StrEql(Records[I].LocalVarName, AName) then
begin
result := I;
Exit;
end;
end;
function TSubLocalVarList.AddRecord: TSubLocalVarRec;
begin
result := TSubLocalVarRec.Create;
L.Add(result);
end;
procedure TSubLocalVarList.SaveToStream(S: TStream);
var
I, K: Integer;
begin
K := Count;
S.Write(K, SizeOf(Integer));
for I := 0 to K - 1 do
with Records[I] do
begin
SaveStringToStream(LocalVarName, S);
SaveStringToStream(LocalVarTypeName, S);
S.Write(LocalVarOffset, SizeOf(LocalVarOffset));
S.Write(IsByRef, SizeOf(IsByRef));
end;
end;
procedure TSubLocalVarList.LoadFromStream(S: TStream);
var
I, K: Integer;
R: TSubLocalVarRec;
begin
S.Read(K, SizeOf(Integer));
for I := 0 to K - 1 do
begin
R := AddRecord;
with R do
begin
LocalVarName := LoadStringFromStream(S);
LocalVarTypeName := LoadStringFromStream(S);
S.Read(LocalVarOffset, SizeOf(LocalVarOffset));
S.Read(IsByRef, SizeOf(IsByRef));
end;
end;
end;
// TSubParamList ---------------------------------------------------------------
function TSubParamList.GetRecord(I: Integer): TSubParamRec;
begin
result := TSubParamRec(L[I]);
end;
function TSubParamList.IndexOf(const AName: String): Integer;
var
I: Integer;
begin
result := -1;
for I := 0 to Count - 1 do
if StrEql(Records[I].ParamName, AName) then
begin
result := I;
Exit;
end;
end;
function TSubParamList.AddRecord: TSubParamRec;
begin
result := TSubParamRec.Create;
L.Add(result);
end;
procedure TSubParamList.SaveToStream(S: TStream);
var
I, K: Integer;
begin
K := Count;
S.Write(K, SizeOf(Integer));
for I := 0 to K - 1 do
with Records[I] do
begin
S.Write(FinTypeId, SizeOf(FinTypeId));
S.Write(ParamMod, SizeOf(ParamMod));
S.Write(ParamSize, SizeOf(ParamSize));
SaveStringToStream(ParamName, S);
SaveStringToStream(ParamTypeName, S);
SaveStringToStream(OptValue, S);
{$IFDEF PCU_EX}
S.Write(ParamOffset, SizeOf(ParamOffset));
{$ENDIF}
end;
end;
procedure TSubParamList.LoadFromStream(S: TStream);
var
I, K: Integer;
R: TSubParamRec;
begin
S.Read(K, SizeOf(Integer));
for I := 0 to K - 1 do
begin
R := AddRecord;
with R do
begin
S.Read(FinTypeId, SizeOf(FinTypeId));
S.Read(ParamMod, SizeOf(ParamMod));
S.Read(ParamSize, SizeOf(ParamSize));
ParamName := LoadStringFromStream(S);
ParamTypeName := LoadStringFromStream(S);
OptValue := LoadStringFromStream(S);
{$IFDEF PCU_EX}
S.Read(ParamOffset, SizeOf(ParamOffset));
{$ENDIF}
end;
end;
end;
// TSubDesc --------------------------------------------------------------------
constructor TSubDesc.Create;
begin
inherited;
ParamList := TSubParamList.Create;
LocalVarList := TSubLocalVarList.Create;
end;
destructor TSubDesc.Destroy;
begin
FreeAndNil(ParamList);
FreeAndNil(LocalVarList);
inherited;
end;
procedure TSubDesc.SaveToStream(S: TStream);
begin
S.Write(OverCount, SizeOf(OverCount));
S.Write(CallConv, SizeOf(CallConv));
S.Write(CallMode, SizeOf(CallMode));
S.Write(ResTypeId, SizeOf(ResTypeId));
S.Write(MethodIndex, SizeOf(MethodIndex));
S.Write(RetSize, SizeOf(RetSize));
S.Write(IsMethod, SizeOf(IsMethod));
S.Write(IsShared, SizeOf(IsShared));
SaveStringToStream(ResTypeName, S);
ParamList.SaveToStream(S);
SaveStringToStream(SubName, S);
SaveStringToStream(DllName, S);
SaveStringToStream(AliasName, S);
{$IFDEF PCU_EX}
LocalVarList.SaveToStream(S);
S.Write(SId, SizeOf(SId));
S.Write(N1, SizeOf(N1));
S.Write(N2, SizeOf(N2));
S.Write(SelfOffset, SizeOf(SelfOffset));
{$ENDIF}
end;
procedure TSubDesc.LoadFromStream(S: TStream);
begin
S.Read(OverCount, SizeOf(OverCount));
S.Read(CallConv, SizeOf(CallConv));
S.Read(CallMode, SizeOf(CallMode));
S.Read(ResTypeId, SizeOf(ResTypeId));
S.Read(MethodIndex, SizeOf(MethodIndex));
S.Read(RetSize, SizeOf(RetSize));
S.Read(IsMethod, SizeOf(IsMethod));
S.Read(IsShared, SizeOf(IsShared));
ResTypeName := LoadStringFromStream(S);
ParamList.Clear;
ParamList.LoadFromStream(S);
SubName := LoadStringFromStream(S);
DllName := LoadStringFromStream(S);
AliasName := LoadStringFromStream(S);
{$IFDEF PCU_EX}
LocalVarList.Clear;
LocalVarList.LoadFromStream(S);
S.Read(SId, SizeOf(SId));
S.Read(N1, SizeOf(N1));
S.Read(N2, SizeOf(N2));
S.Read(SelfOffset, SizeOf(SelfOffset));
{$ENDIF}
end;
// TSubDescList ----------------------------------------------------------------
function TSubDescList.GetRecord(I: Integer): TSubDesc;
begin
result := TSubDesc(L[I]);
end;
function TSubDescList.AddRecord: TSubDesc;
begin
result := TSubDesc.Create;
L.Add(result);
end;
procedure TSubDescList.SaveToStream(S: TStream);
var
I, K: Integer;
begin
K := Count;
S.Write(K, SizeOf(Integer));
for I := 0 to K - 1 do
Records[I].SaveToStream(S);
end;
procedure TSubDescList.LoadFromStream(S: TStream);
var
I, K: Integer;
begin
S.Read(K, SizeOf(Integer));
for I := 0 to K - 1 do
AddRecord.LoadFromStream(S);
end;
// TTypeMapRec -----------------------------------------------------------------
constructor TTypeMapRec.Create;
begin
inherited;
Fields := TIntegerList.Create;
end;
destructor TTypeMapRec.Destroy;
begin
FreeAndNil(Fields);
inherited;
end;
// TTypeMap --------------------------------------------------------------------
function TTypeMap.Lookup(TypeId: Integer): TTypeMapRec;
var
I: Integer;
begin
result := nil;
for I := 0 to Count - 1 do
if Records[I].TypeId = TypeId then
begin
result := Records[I];
Exit;
end;
end;
function TTypeMap.GetRecord(I: Integer): TTypeMapRec;
begin
result := TTypeMapRec(L[I]);
end;
function TTypeMap.Add(TypeId: Integer): TTypeMapRec;
begin
result := Lookup(TypeId);
if result <> nil then
Exit;
result := TTypeMapRec.Create;
result.TypeId := TypeId;
L.Add(result);
end;
// TMapFieldRec ----------------------------------------------------------------
procedure TMapFieldRec.SaveToStream(S: TStream);
begin
SaveStringToStream(FieldName, S);
S.Write(FieldOffset, SizeOf(FieldOffset));
{$IFDEF PCU_EX}
SaveStringToStream(FieldTypeName, S);
{$ENDIF}
end;
procedure TMapFieldRec.LoadFromStream(S: TStream);
begin
FieldName := LoadStringFromStream(S);
S.Read(FieldOffset, SizeOf(FieldOffset));
{$IFDEF PCU_EX}
FieldTypeName := LoadStringFromStream(S);
{$ENDIF}
end;
// TMapFieldList ---------------------------------------------------------------
function TMapFieldList.GetRecord(I: Integer): TMapFieldRec;
begin
result := TMapFieldRec(L[I]);
end;
function TMapFieldList.Lookup(const FieldName: String): TMapFieldRec;
var
I: Integer;
begin
result := nil;
for I := 0 to Count - 1 do
if StrEql(Records[I].FieldName, FieldName) then
begin
result := Records[I];
Exit;
end;
end;
procedure TMapFieldList.SaveToStream(S: TStream);
var
I, K: Integer;
begin
K := Count;
S.Write(K, SizeOf(K));
for I := 0 to Count - 1 do
Records[I].SaveToStream(S);
end;
procedure TMapFieldList.LoadFromStream(S: TStream);
var
I, K: Integer;
R: TMapFieldRec;
begin
S.Read(K, SizeOf(K));
for I := 0 to K - 1 do
begin
R := TMapFieldRec.Create;
R.LoadFromStream(S);
L.Add(R);
end;
end;
function TMapFieldList.Add(const FieldName: String;
FieldOffset: Integer;
const FieldTypeName: String): TMapFieldRec;
begin
result := TMapFieldRec.Create;
result.FieldName := FieldName;
result.FieldOffset := FieldOffset;
{$IFDEF PCU_EX}
result.FieldTypeName := FieldTypeName;
{$ENDIF}
L.Add(result);
end;
// TMapRec ---------------------------------------------------------------------
constructor TMapRec.Create;
begin
inherited;
FieldList := nil;
SubDesc := TSubDesc.Create;
end;
destructor TMapRec.Destroy;
begin
if Assigned(FieldList) then
FreeAndNil(FieldList);
FreeAndNil(SubDesc);
inherited;
end;
function TMapRec.GetIsMethod: Boolean;
begin
result := SubDesc.IsMethod;
end;
procedure TMapRec.SaveToStream(S: TStream);
begin
SaveStringToStream(FullName, S);
S.Write(Offset, SizeOf(Offset));
S.Write(ClassIndex, SizeOf(ClassIndex));
S.Write(Kind, SizeOf(Kind));
S.Write(Global, SizeOf(Global));
S.Write(Vis, SizeOf(Vis));
S.Write(TypedConst, SizeOf(TypedConst));
S.Write(IsExternal, SizeOf(IsExternal));
SaveStringToStream(FullTypeName, S);
SubDesc.SaveToStream(S);
if ClassIndex > 0 then
FieldList.SaveToStream(S);
end;
procedure TMapRec.LoadFromStream(S: TStream);
begin
FullName := LoadStringFromStream(S);
S.Read(Offset, SizeOf(Offset));
S.Read(ClassIndex, SizeOf(ClassIndex));
S.Read(Kind, SizeOf(Kind));
S.Read(Global, SizeOf(Global));
S.Read(Vis, SizeOf(Vis));
S.Read(TypedConst, SizeOf(TypedConst));
S.Read(IsExternal, SizeOf(IsExternal));
FullTypeName := LoadStringFromStream(S);
SubDesc.LoadFromStream(S);
if ClassIndex > 0 then
begin
if Assigned(FieldList) then
FreeAndNil(FieldList);
FieldList := TMapFieldList.Create;
FieldList.LoadFromStream(S);
end;
end;
// TMapTable ------------------------------------------------------------------------
function TMapTable.GetRecord(I: Integer): TMapRec;
begin
result := TMapRec(L[I]);
end;
function TMapTable.Add: TMapRec;
begin
result := TMapRec.Create;
L.Add(result);
end;
function TMapTable.AddRec(const FullName: String;
Shift: Integer; ClassIndex: Integer;
Kind: Byte;
Global: Boolean;
OverCount: Byte;
CallMode: Byte): TMapRec;
begin
result := Add;
result.FullName := FullName;
result.Shift := Shift;
result.ClassIndex := ClassIndex;
result.Kind := Kind;
result.Global := Global;
result.SubDesc.OverCount := OverCount;
result.SubDesc.CallMode := CallMode;
if ClassIndex > 0 then
result.FieldList := TMapFieldList.Create;
end;
procedure TMapTable.SaveToStream(S: TStream);
var
I, K: Integer;
begin
K := Count;
S.Write(K, SizeOf(Integer));
for I:=0 to K - 1 do
Records[I].SaveToStream(S);
end;
procedure TMapTable.LoadFromStream(S: TStream);
var
I, K: Integer;
R: TMapRec;
begin
Clear;
S.Read(K, SizeOf(Integer));
for I:=0 to K - 1 do
begin
R := Add;
R.LoadFromStream(S);
end;
end;
function TMapTable.Lookup(const FullName: String): TMapRec;
var
I: Integer;
S: String;
begin
result := nil;
for I:=0 to Count - 1 do
if StrEql(Records[I].FullName, FullName) then
begin
result := Records[I];
Exit;
end;
if ChCount(FullName, '.') <> 1 then
Exit;
for I:=0 to Count - 1 do
begin
S := Records[I].FullName;
if ChCount(S, '.') = 2 then
if StrEql(FullName, ExtractFullName(S)) then
begin
result := Records[I];
Exit;
end;
end;
end;
function TMapTable.LookupEx(const FullName: String; OverCount: Integer): TMapRec;
var
I: Integer;
S: String;
begin
result := nil;
for I:=0 to Count - 1 do
begin
if Records[I].Kind in KindSUBS then
begin
if Records[I].SubDesc.OverCount = OverCount then
if StrEql(Records[I].FullName, FullName) then
begin
result := Records[I];
Exit;
end;
end
else
begin
if StrEql(Records[I].FullName, FullName) then
begin
result := Records[I];
Exit;
end;
end;
end;
if ChCount(FullName, '.') <> 1 then
Exit;
for I:=0 to Count - 1 do
if Records[I].Kind in KindSUBS then
begin
if Records[I].SubDesc.OverCount = OverCount then
begin
S := Records[I].FullName;
if ChCount(S, '.') = 2 then
if StrEql(FullName, ExtractFullName(S)) then
begin
result := Records[I];
Exit;
end;
end;
end
else
begin
S := Records[I].FullName;
if ChCount(S, '.') = 2 then
if StrEql(FullName, ExtractFullName(S)) then
begin
result := Records[I];
Exit;
end;
end;
end;
function TMapTable.LookupByOffset(Offset: Integer): TMapRec;
var
I: Integer;
begin
result := nil;
for I:=0 to Count - 1 do
if Records[I].Offset = Offset then
begin
result := Records[I];
Exit;
end;
end;
function TMapTable.LookupConstructor(const AClassName: String; NP: Integer): TMapRec;
var
I: Integer;
S: String;
MR: TMapRec;
begin
result := nil;
for I:=0 to Count - 1 do
begin
MR := Records[I];
if MR.Kind = kindCONSTRUCTOR then
if MR.SubDesc.ParamList.Count = NP then
begin
S := ExtractClassName(MR.FullName);
if StrEql(S, AClassName) then
begin
result := MR;
Exit;
end;
end;
end;
end;
function TMapTable.LookupType(const FullName: String): TMapRec;
var
I: Integer;
S1, S2: String;
begin
result := nil;
S1 := ExtractName(FullName);
for I:=0 to Count - 1 do
if Records[I].Kind = kindTYPE then
begin
S2 := ExtractName(Records[I].FullName);
if StrEql(S1, S2) then
begin
result := Records[I];
Exit;
end;
end;
end;
function TMapTable.LookupSub(SubId: Integer): TMapRec;
var
I: Integer;
MR: TMapRec;
begin
result := nil;
for I:=0 to Count - 1 do
begin
MR := Records[I];
if MR.Kind in kindSUBS then
if MR.SubDesc.SId = SubId then
begin
result := MR;
Exit;
end;
end;
end;
procedure TMapTable.CreateOffsets(OffsetList: TOffsetList; Host: Boolean);
var
I, S, Q: Integer;
MapRec: TMapRec;
begin
if OffsetList.Count > 0 then
for I := 0 to Count - 1 do
begin
MapRec := Records[I];
if (not Host) and (MapRec.Kind in KindSUBS) then
begin
MapRec.Offset := MapRec.Shift;
continue;
end;
S := MapRec.Shift;
if S > 0 then
begin
Q := OffsetList.GetOffset(S);
if Q = -1 then
raise Exception.Create(errInternalError);
MapRec.Offset := Q;
end;
end
else
for I := 0 to Count - 1 do
begin
MapRec := Records[I];
MapRec.Offset := MapRec.Shift;
end;
end;
function TMapTable.GetSub(N: Integer): TMapRec;
var
I: Integer;
MR: TMapRec;
begin
result := nil;
for I := 0 to Count - 1 do
begin
MR := Records[I];
if MR.Kind in KindSUBS then
if (N >= MR.SubDesc.N1) and (N <= MR.SubDesc.N2) then
begin
result := MR;
Exit;
end;
end;
end;
end.