Simba/Units/Misc/PSDump.pas

348 lines
11 KiB
Plaintext

{
@abstract(Component wrapper for IFPS3 compiler and executer)
A component wrapper for IFPS3, including debugging support.
}
unit PSDump;
{$IFDEF FPC}
{$H+}
{$ENDIF}
interface
uses
SysUtils, Classes, uPSRuntime, uPSUtils, uPSComponent,
uPSCompiler, uPSC_dll, typInfo;
type
TPSOnCompCleanup = function (Sender: TObject; aComp: TPSPascalCompiler): Boolean of object;
TPSOnException = procedure (Sender: TPSExec; ExError: TPSError; const ExParam: tbtstring; ExObject: TObject; ProcNo, Position: Cardinal) of object;
TPSScriptExtension = class(TPSScriptDebugger)
private
FOnBeforeCleanUp: TPSOnCompCleanup;
FNeedCompiling: Boolean;
FOnScriptChange: TNotifyEvent;
FOnException: TPSOnException;
fItems: TStrings;
procedure GetCodeProps;
protected
function DoBeforeCleanup(Sender: TObject; aComp: TPSPascalCompiler):Boolean;
procedure DoScriptChange(sender:TObject);
public
constructor Create(AOwner: TComponent); override;
function Compile: Boolean; override;
function Execute: Boolean; override;
procedure GetValueDefs(aItems: TStrings);
procedure CompileIfNeeded;
property NeedCompiling : Boolean read FNeedCompiling;
published
property OnBeforeCleanUp: TPSOnCompCleanup read FOnBeforeCleanUp write FOnBeforeCleanUp;
Property OnScriptChange: TNotifyEvent read FOnScriptChange write fOnScriptChange;
property OnException: TPSOnException read FOnException write FOnException;
end;
implementation
function BeforeCleanup(Sender: TPSPascalCompiler): Boolean;
begin
Result := TPSScriptExtension(Sender.ID).DoBeforeCleanUp(TObject(Sender.ID),Sender);
end;
procedure CEException(Sender: TPSExec; ExError: TIFError; const ExParam: tbtstring; ExObject: TObject; ProcNo, Position: Cardinal);
begin
if (TPSScriptExtension(Sender.ID).FOnException <> nil) then
TPSScriptExtension(Sender.ID).FOnException(Sender, ExError, ExParam, ExObject, ProcNo, Position);
end;
{ TPSScriptExtension }
function TPSScriptExtension.Compile: Boolean;
begin
Result := inherited Compile;
FNeedCompiling := not result;
end;
constructor TPSScriptExtension.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
Comp.OnBeforeCleanup := {$IFDEF FPC}@{$ENDIF}BeforeCleanup;
Exec.OnException := {$IFDEF FPC}@{$ENDIF}CEException;
TStringList(script).OnChange := {$IFDEF FPC}@{$ENDIF}DoScriptChange;
FNeedCompiling := True;
end;
type
_TMyPascalCompiler = class(TPSPascalCompiler);
procedure TPSScriptExtension.GetCodeProps;
function TypeToString(t: TPSType; Definition: Boolean = False): tbtstring; forward;
function FunctionType(f: TObject): tbtstring;
const
FuncStr: array[Boolean] of tbtstring = ('procedure', 'function');
begin
if (f is TPSDelphiClassItemConstructor) then
Result := 'constructor'
else if (f is TPSDelphiClassItemMethod) then
Result := FuncStr[TPSDelphiClassItemMethod(f).Decl.Result <> nil]
else if (f is TPSProceduralType) then
Result := FuncStr[TPSProceduralType(f).ProcDef.Result <> nil]
else if (f is TPSRegProc) then
Result := FuncStr[TPSRegProc(f).Decl.Result <> nil]
else if (f is TPSInternalProcedure) then
Result := FuncStr[TPSInternalProcedure(f).Decl.Result <> nil]
else
Result := '';
end;
function ParamsToString(d: TPSParametersDecl; CheckResult: Boolean = True): tbtstring;
const
ParamStr: array [pmIn..pmInOut] of tbtstring = ('','out ','var ');
var
i: Integer;
begin
Result := '';
for i := 0 to d.ParamCount - 1 do
begin
if (Result <> '') then
Result := Result + '; ';
Result := Result + ParamStr[d.Params[i].Mode] + d.Params[i].OrgName;
if (d.Params[i].aType <> nil) then
Result := Result +': '+ TypeToString(d.Params[i].aType);
end;
if (Result <> '') then
Result := '('+Result+')';
if CheckResult and (d.Result <> nil) then
Result := Result + ': ' + TypeToString(d.Result);
end;
function ClassItemsToString(c: TPSCompileTimeClass; DoneList: TStrings = nil): tbtstring;
var
ci: TPSDelphiClassItem;
i, ii: Integer;
s: tbtstring;
Def: PtrUInt;
ListFree: Boolean;
begin
Result := '';
if (c = nil) then
Exit;
if (DoneList = nil) then
begin
DoneList := TStringList.Create;
TStringList(DoneList).Sorted := True;
ListFree := True;
end
else
ListFree := False;
if (not c.Property_Find('', Def)) then
Def := 0;
for i := 0 to c.Count - 1 do
begin
ci := c.Items[i];
If (ci = nil) or (DoneList.IndexOf(ci.OrgName) > -1) then
Continue;
DoneList.Add(ci.OrgName);
if (ci is TPSDelphiClassItemConstructor) or (ci is TPSDelphiClassItemMethod) then
Result := Result + FunctionType(ci) + ' ' + ci.OrgName + ParamsToString(ci.Decl, not (ci is TPSDelphiClassItemConstructor)) + '; '
else if (ci is TPSDelphiClassItemProperty) then
begin
s := '';
for ii := 0 to ci.Decl.ParamCount - 1 do
begin
if (s <> '') then
s := s + ', ';
s := s + 'Index';
if (ii > 0) then
s := s + IntToStr(ii + 1);
if (ii = ci.Decl.ParamCount - 1) then
s := s + ': ' + TypeToString(ci.Decl.Params[ii].aType);
end;
if (s <> '') then
s := '['+s+']';
Result := Result + 'property ' + ci.OrgName + s;
if (ci.Decl.Result <> nil) then
Result := Result + ': '+ TypeToString(ci.Decl.Result);
if (PtrUInt(ci) = Def) then
Result := Result + '; default';
Result := Result + '; ';
end;
end;
Result := Result + ClassItemsToString(c.ClassInheritsFrom, DoneList);
if ListFree then
DoneList.Free;
end;
function TypeToString(t: TPSType; Definition: Boolean = False): tbtstring;
var
r: PIFPSRecordFieldTypeDef;
i: Integer;
begin
if (not Definition) and (t.OriginalName <> '') and (t.OriginalName[1] <> '!') then
Result := t.OriginalName
else if (t is TPSRecordType) then
begin
Result := 'record ';
for i := 0 to (t as TPSRecordType).RecValCount - 1 do
begin
r := (t as TPSRecordType).RecVal(i);
Result := Result + r.FieldOrgName + ': ' + TypeToString(r.aType) + '; ';
end;
Result := Result + 'end';
end
else if (t is TPSClassType) then
Result := 'class ' + ClassItemsToString((t as TPSClassType).Cl) + 'end'
else if (t is TPSProceduralType) then
Result := FunctionType(t) + ParamsToString((t as TPSProceduralType).ProcDef)
else if (t is TPSArrayType) then
Result := 'array of ' + TypeToString((t as TPSArrayType).ArrayTypeNo)
else if (t is TPSStaticArrayType) then
with (t as TPSStaticArrayType) do
Result := 'array[' + IntToStr(StartOffset) + '..' + IntToStr(StartOffset + Length) + ' of ' + TypeToString(ArrayTypeNo)
else if (t is TPSSetType) then
Result := 'set of ' + TypeToString((t as TPSSetType).SetType)
else if (t is TPSTypeLink) then
Result := TypeToString((t as TPSTypeLink).LinkTypeNo)
else if (t is TPSEnumType) then
begin
Result := '';
for i := 0 to t.Attributes.Count - 1 do
begin
if (Result <> '') then
Result := Result + ', ';
Result := Result + TPSConstant(t.Attributes[i].AType).OrgName;
end;
if (Result <> '') then
Result := '('+Result+')'
else
Result := 'enum';
end
else
Result := t.OriginalName;
end;
function IfRVariantToString(v: TIfRVariant): tbtstring;
begin
case v.FType.BaseType of
btU8: Result := IntToStr(v.tu8);
btS8: Result := IntToStr(v.ts8);
btU16: Result := IntToStr(v.tu16);
btS16: Result := IntToStr(v.ts16);
btU32: Result := IntToStr(v.tu32);
btS32: Result := IntToStr(v.ts32);
btSingle: Result := FloatToStr(v.tsingle);
btDouble: Result := FloatToStr(v.tdouble);
btExtended: Result := FloatToStr(v.textended);
btString: Result := MakeString(tbtString(v.tstring));
{$IFNDEF PS_NOINT64}
btS64: Result := IntToStr(v.ts64);
{$ENDIF}
btChar: Result := '#' + IntToStr(Ord(v.tchar));
{$IFNDEF PS_NOWIDESTRING}
btWideString: Result := tbtwidestring(v.twidestring);
btWideChar: Result := '#' + IntToStr(Ord(v.twidechar));
{$ENDIF}
btCurrency: Result := FloatToStr(v.tcurrency);
btUnicodeString: Result := tbtunicodestring(v.tunistring);
else
Result := v.FType.OriginalName;
end;
end;
var
i : Integer;
begin
if (fItems = nil) then
Exit;
fItems.BeginUpdate;
try
fItems.Clear;
with _TMyPascalCompiler(Comp) do
begin
for i := 0 to FConstants.Count - 1 do
with TPSConstant(FConstants[i]) do
if (Value^.FType is TPSEnumType) then
Value^.FType.Attributes.Add(TPSAttributeType(FConstants[i]))
else
fItems.Add('const ' + OrgName + ' = ' + IfRVariantToString(Value^) + ';');
for i := 0 to FTypes.Count - 1 do
with TPSType(FTypes[i]) do
if (OriginalName <> '') and (OriginalName[1] <> '!') then
fItems.Add('type ' + OriginalName + ' = ' + TypeToString(TPSType(FTypes[i]), True) + ';');
for i := 0 to FVars.Count - 1 do
with TPSVar(FVars[i]) do
fItems.Add('var ' + OrgName + ': ' + TypeToString(TPSType(FVars[i]), True) + ';');
for i := 0 to FRegProcs.Count - 1 do
with TPSRegProc(FRegProcs[i]) do
fItems.Add(FunctionType(TObject(FRegProcs[i])) + ' ' + OrgName + ParamsToString(Decl) + '; forward;');
for i := 0 to FProcs.Count - 1 do
if (TPSProcedure(FProcs[i]) is TPSInternalProcedure) then
with TPSInternalProcedure(FProcs[i]) do
if (Name <> '') and (Name[1] <> '!') then
fItems.Add(FunctionType(TObject(FProcs[i])) + ' ' + OriginalName + ParamsToString(Decl) + '; forward;');
end;
finally
fItems.EndUpdate;
end;
end;
procedure TPSScriptExtension.GetValueDefs(aItems: TStrings);
begin
fItems := aItems;
try
Compile;
finally
fItems := nil;
end;
end;
function TPSScriptExtension.DoBeforeCleanup(Sender: TObject; aComp: TPSPascalCompiler): Boolean;
begin
Result := True;
if (fItems <> nil) then
GetCodeProps;
if (FOnBeforeCleanUp <> nil) then
Result := FOnBeforeCleanUp(Sender, aComp);
end;
function TPSScriptExtension.Execute: Boolean;
begin
CompileIfNeeded;
Result := inherited Execute;
end;
procedure TPSScriptExtension.DoScriptChange(sender: TObject);
begin
FNeedCompiling := True;
if (FOnScriptChange <> nil) then
FOnScriptChange(sender);
end;
procedure TPSScriptExtension.CompileIfNeeded;
begin
if FNeedCompiling then
Compile;
end;
end.