DBG: implemented "Repeat Count" for watches

git-svn-id: trunk@37455 -
This commit is contained in:
martin 2012-05-29 20:46:36 +00:00
parent 6f93a15f00
commit bbf31875cd
4 changed files with 201 additions and 37 deletions

View File

@ -1069,6 +1069,7 @@ type
private
FDisplayFormat: TWatchDisplayFormat;
FEvaluateFlags: TDBGEvaluateFlags;
FRepeatCount: Integer;
FStackFrame: Integer;
FThreadId: Integer;
FValidity: TDebuggerDataState;
@ -1096,6 +1097,7 @@ type
procedure Assign(AnOther: TWatchValue);
property DisplayFormat: TWatchDisplayFormat read FDisplayFormat;
property EvaluateFlags: TDBGEvaluateFlags read FEvaluateFlags;
property RepeatCount: Integer read FRepeatCount;
property ThreadId: Integer read FThreadId;
property StackFrame: Integer read FStackFrame;
property Watch: TWatch read FWatch;
@ -1140,10 +1142,12 @@ type
FEvaluateFlags: TDBGEvaluateFlags;
FExpression: String;
FDisplayFormat: TWatchDisplayFormat;
FRepeatCount: Integer;
FValueList: TWatchValueList;
function GetEnabled: Boolean;
function GetValue(const AThreadId: Integer; const AStackFrame: Integer): TWatchValue;
procedure SetEvaluateFlags(AValue: TDBGEvaluateFlags);
procedure SetRepeatCount(AValue: Integer);
protected
procedure AssignTo(Dest: TPersistent); override;
function CreateValueList: TWatchValueList; virtual;
@ -1172,6 +1176,7 @@ type
property Expression: String read GetExpression write SetExpression;
property DisplayFormat: TWatchDisplayFormat read GetDisplayFormat write SetDisplayFormat;
property EvaluateFlags: TDBGEvaluateFlags read FEvaluateFlags write SetEvaluateFlags;
property RepeatCount: Integer read FRepeatCount write SetRepeatCount;
public
property Values[const AThreadId: Integer; const AStackFrame: Integer]: TWatchValue
read GetValue;
@ -4598,6 +4603,7 @@ begin
Result := TWatchValue(FList[i]);
if (Result.ThreadId = AThreadId) and (Result.StackFrame = AStackFrame) and
(Result.DisplayFormat = FWatch.DisplayFormat) and
(Result.RepeatCount = FWatch.RepeatCount) and
(Result.EvaluateFlags = FWatch.EvaluateFlags)
then
exit;
@ -4764,6 +4770,7 @@ begin
if AConfig.GetValue(APath + 'ClassAutoCast', False)
then Include(FEvaluateFlags, defClassAutoCast)
else Exclude(FEvaluateFlags, defClassAutoCast);
FRepeatCount := AConfig.GetValue(APath + 'RepeatCount', 0);
try ReadStr(AConfig.GetValue(APath + 'DisplayFormat', 'wdfDefault'), FDisplayFormat);
except FDisplayFormat := wdfDefault; end;
try ReadStr(AConfig.GetValue(APath + 'Validity', 'ddsValid'), FValidity);
@ -4782,6 +4789,7 @@ begin
WriteStr(s, FValidity);
AConfig.SetDeleteValue(APath + 'Validity', s, 'ddsValid');
AConfig.SetDeleteValue(APath + 'ClassAutoCast', defClassAutoCast in FEvaluateFlags, False);
AConfig.SetDeleteValue(APath + 'RepeatCount', FRepeatCount, 0);
end;
constructor TWatchValue.Create;
@ -4798,6 +4806,7 @@ begin
FWatch := AOwnerWatch;
FDisplayFormat := FWatch.DisplayFormat;
FEvaluateFlags := FWatch.EvaluateFlags;
FRepeatCount := FWatch.RepeatCount;
Create;
end;
@ -8205,6 +8214,14 @@ begin
DoModified;
end;
procedure TWatch.SetRepeatCount(AValue: Integer);
begin
if FRepeatCount = AValue then Exit;
FRepeatCount := AValue;
Changed;
DoModified;
end;
function TWatch.GetDisplayFormat: TWatchDisplayFormat;
begin
Result := FDisplayFormat;
@ -8226,6 +8243,7 @@ begin
else Exclude(FEvaluateFlags, defClassAutoCast);
try ReadStr(AConfig.GetValue(APath + 'DisplayFormat', 'wdfDefault'), FDisplayFormat);
except FDisplayFormat := wdfDefault; end;
FRepeatCount := AConfig.GetValue(APath + 'RepeatCount', 0);
FValueList.LoadDataFromXMLConfig(AConfig, APath + 'ValueList/');
end;
@ -8239,6 +8257,7 @@ begin
WriteStr(s{%H-}, FDisplayFormat);
AConfig.SetDeleteValue(APath + 'DisplayFormat', s, 'wdfDefault');
AConfig.SetDeleteValue(APath + 'ClassAutoCast', defClassAutoCast in FEvaluateFlags, False);
AConfig.SetDeleteValue(APath + 'RepeatCount', FRepeatCount, 0);
FValueList.SaveDataToXMLConfig(AConfig, APath + 'ValueList/');
end;
@ -8279,6 +8298,7 @@ begin
if FSnapShot = nil then begin
TCurrentWatchValueList(FValueList).SnapShot := nil;
end else begin
// TODO: FValueList is copied twice ?
FSnapShot.Assign(self);
FSnapShot.Enabled := True; // Snapshots are always enabled
TCurrentWatchValueList(FValueList).SnapShot := FSnapShot.FValueList;
@ -8340,6 +8360,7 @@ begin
if i >= 0
then DisplayFormat := TWatchDisplayFormat(i)
else DisplayFormat := wdfDefault;
FRepeatCount := AConfig.GetValue(APath + 'RepeatCount', 0);
end;
procedure TCurrentWatch.SaveToXMLConfig(const AConfig: TXMLConfig; const APath: string);
@ -8349,6 +8370,7 @@ begin
AConfig.SetDeleteValue(APath + 'DisplayStyle/Value',
TWatchDisplayFormatNames[DisplayFormat], TWatchDisplayFormatNames[wdfDefault]);
AConfig.SetDeleteValue(APath + 'ClassAutoCast', defClassAutoCast in FEvaluateFlags, False);
AConfig.SetDeleteValue(APath + 'RepeatCount', FRepeatCount, 0);
end;
{ =========================================================================== }

View File

@ -259,7 +259,8 @@ type
function GetWideText(const ALocation: TDBGPtr): String;
function GetGDBTypeInfo(const AExpression: String; FullTypeInfo: Boolean = False;
AFlags: TGDBTypeCreationFlags = [];
AFormat: TWatchDisplayFormat = wdfDefault): TGDBType;
AFormat: TWatchDisplayFormat = wdfDefault;
ARepeatCount: Integer = 0): TGDBType;
function GetClassName(const AClass: TDBGPtr): String; overload;
function GetClassName(const AExpression: String; const AValues: array of const): String; overload;
function GetInstanceClassName(const AInstance: TDBGPtr): String; overload;
@ -10402,8 +10403,8 @@ begin
end;
function TGDBMIDebuggerCommand.GetGDBTypeInfo(const AExpression: String;
FullTypeInfo: Boolean = False; AFlags: TGDBTypeCreationFlags = [];
AFormat: TWatchDisplayFormat = wdfDefault): TGDBType;
FullTypeInfo: Boolean; AFlags: TGDBTypeCreationFlags; AFormat: TWatchDisplayFormat;
ARepeatCount: Integer): TGDBType;
var
R: TGDBMIExecResult;
f: Boolean;
@ -10477,7 +10478,7 @@ begin
then AFlags := AFlags + [gtcfClassIsPointer];
if FullTypeInfo
then AFlags := AFlags + [gtcfFullTypeInfo];
Result := TGdbType.CreateForExpression(AExpression, AFlags);
Result := TGdbType.CreateForExpression(AExpression, AFlags, wdfDefault, ARepeatCount);
while not Result.ProcessExpression do begin
if Result.EvalError
then break;
@ -12094,7 +12095,7 @@ var
ResultList: TGDBMINameValueList;
R: TGDBMIExecResult;
MemDump: TGDBMIMemoryDumpResultList;
Size: integer;
i, Size: integer;
s: String;
begin
Result := False;
@ -12225,8 +12226,10 @@ var
begin
Result := False;
Assert(FTypeInfo = nil, 'Type info must be nil');
i := 0;
if FWatchValue <> nil then i := FWatchValue.RepeatCount;
FTypeInfo := GetGDBTypeInfo(AnExpression, defFullTypeInfo in FEvalFlags,
TypeInfoFlags + [gtcfExprEvaluate, gtcfExprEvalStrFixed], FDisplayFormat);
TypeInfoFlags + [gtcfExprEvaluate, gtcfExprEvalStrFixed], FDisplayFormat, i);
if (FTypeInfo = nil) or (dcsCanceled in SeenStates)
then begin

View File

@ -311,7 +311,8 @@ type
gtcfExprIsType,
gtcfExprEvaluate,
gtcfExprEvalStrFixed, // Evaluate with string fix, if needed; only if gtcfExprEvaluate is set
gtcfAutoCastClass // Find real class of instance, and use, instead of declared class of variable
gtcfAutoCastClass, // Find real class of instance, and use, instead of declared class of variable
gtcfForceArrayEval // Used by RepeatCount, in case of "SomePointer[i]"
);
TGDBTypeCreationFlags = set of TGDBTypeCreationFlag;
@ -320,7 +321,8 @@ type
gtpsSimplePointer,
gtpsClass, gtpsClassAutoCast, gtpsClassPointer, gtpsClassAncestor,
gtpsArray,
gtpsEvalExpr, gtpsEvalExprArray, gtpsEvalExprDynArray, gtpsEvalExprDynArrayGetData,
gtpsEvalExpr, gtpsEvalExprRepeated,
gtpsEvalExprArray, gtpsEvalExprDynArray, gtpsEvalExprDynArrayGetData,
gtpsFinished
);
@ -348,14 +350,17 @@ type
FExprEvaluatedAsText: String;
FHasExprEvaluatedAsText: Boolean;
FExprEvaluateFormat: TWatchDisplayFormat;
FRepeatCount: Integer;
// Sub-Types (FNext is managed by creator / linked list)
FFirstProcessingSubType, FNextProcessingSubType: TGDBType;
FRepeatFirstIndex: Integer;
FStringExprEvaluatedAsText: String;
FTypeInfoAncestor: TGDBType;
FArrayIndexValues: Array of TGDBType;
FArrayIndexValueLimit: Integer;
FRepeatCountEval: TGDBType;
// Gdb-Requests
FEvalError: boolean;
@ -377,10 +382,13 @@ type
function IsReqError(AReqType: TGDBTypeProcessRequest; CheckResKind: Boolean = True): Boolean;
protected
procedure Init; override;
function DebugString: String;
property RepeatFirstIndex: Integer read FRepeatFirstIndex write FRepeatFirstIndex;
public
constructor CreateForExpression(const AnExpression: string;
const AFlags: TGDBTypeCreationFlags;
AFormat: TWatchDisplayFormat = wdfDefault);
AFormat: TWatchDisplayFormat = wdfDefault;
ARepeatCount: Integer = 0);
destructor Destroy; override;
function ProcessExpression: Boolean;
property EvalRequest: PGDBPTypeRequest read FEvalRequest;
@ -404,6 +412,9 @@ function ParseTypeFromGdb(const ATypeText: string): TGDBPTypeResult;
function dbgs(AFlag: TGDBPTypeResultFlag): string; overload;
function dbgs(AFlags: TGDBPTypeResultFlags): string; overload;
function dbgs(AFlag: TGDBTypeCreationFlag): string; overload;
function dbgs(AFlags: TGDBTypeCreationFlags): string; overload;
function dbgs(AState: TGDBTypeProcessState): string; overload;
function dbgs(AKind: TGDBPTypeResultKind): string; overload;
function dbgs(AReqType: TGDBCommandRequestType): string; overload;
function dbgs(AReq: TGDBPTypeRequest): string; overload;
@ -917,6 +928,29 @@ begin
if Result <> '' then Result := '[' + Result + ']';
end;
function dbgs(AFlag: TGDBTypeCreationFlag): string;
begin
writestr(Result, AFlag);
end;
function dbgs(AFlags: TGDBTypeCreationFlags): string;
var
i: TGDBTypeCreationFlag;
begin
Result:='';
for i := low(TGDBTypeCreationFlags) to high(TGDBTypeCreationFlags) do
if i in AFlags then begin
if Result <> '' then Result := Result + ', ';
Result := Result + dbgs(i);
end;
if Result <> '' then Result := '[' + Result + ']';
end;
function dbgs(AState: TGDBTypeProcessState): string;
begin
writestr(Result, AState);
end;
function dbgs(AKind: TGDBPTypeResultKind): string;
begin
writestr(Result, AKind);
@ -2004,8 +2038,13 @@ begin
FParsedExpression := nil;
end;
function TGDBType.DebugString: String;
begin
Result := Format('Expr="%s", Flags=%s, State=%s', [FExpression, dbgs(FCreationFlags), dbgs(FProcessState)]);
end;
constructor TGDBType.CreateForExpression(const AnExpression: string;
const AFlags: TGDBTypeCreationFlags; AFormat: TWatchDisplayFormat = wdfDefault);
const AFlags: TGDBTypeCreationFlags; AFormat: TWatchDisplayFormat; ARepeatCount: Integer);
begin
Create(skSimple, ''); // initialize
FInternalTypeName := '';
@ -2023,6 +2062,9 @@ begin
FHasAutoTypeCastFix := False;
FAutoTypeCastName := '';
FArrayIndexValueLimit := 5;
FRepeatCountEval := nil;
FRepeatCount := ARepeatCount;
FRepeatFirstIndex := 0;
end;
destructor TGDBType.Destroy;
@ -2035,6 +2077,7 @@ begin
FArrayIndexValues[i].Free;
FArrayIndexValues := nil;
FreeAndNil(FParsedExpression);
FreeAndNil(FRepeatCountEval);
end;
function TGDBType.ProcessExpression: Boolean;
@ -2043,6 +2086,7 @@ var
procedure ProcessInitial; forward;
procedure ProcessInitialSimple; forward;
procedure ProcessSimplePointer; forward;
procedure EvaluateExpression; forward;
function ClearAmpersand(s: string): string;
@ -2546,15 +2590,17 @@ var
FExprEvaluatedAsText := FExprEvaluatedAsText + ', ';
FExprEvaluatedAsText := FExprEvaluatedAsText + s;
end;
if FArrayIndexValueLimit < FLen then
if Length(FArrayIndexValues) < FLen then
FExprEvaluatedAsText := FExprEvaluatedAsText + ', ...';
FHasExprEvaluatedAsText := True;
Result := True;
exit;
end;
if (FExprEvaluatedAsText <> '') and
(FExprEvaluatedAsText[1] = '{') // gdb returned array data
(FExprEvaluatedAsText[1] = '{') and // gdb returned array data
not(gtcfForceArrayEval in FCreationFlags)
then begin
if (FLen = 0) or
((Length(FExprEvaluatedAsText) > 1) and (FExprEvaluatedAsText[2] <> '}') )
@ -2565,11 +2611,11 @@ var
end;
// Get Data
m := Min(FArrayIndexValueLimit, FLen);
m := Min(Max(FArrayIndexValueLimit, FRepeatCount), FLen);
SetLength(FArrayIndexValues, m);
for i := 0 to m-1 do begin
FArrayIndexValues[i] := TGDBType.CreateForExpression(FExpression+'['+IntToStr(i)+']',
FCreationFlags + [gtcfExprEvaluate]);
FArrayIndexValues[i] := TGDBType.CreateForExpression(FExpression+'['+IntToStr(FRepeatFirstIndex + i)+']',
FCreationFlags + [gtcfExprEvaluate] - [gtcfForceArrayEval]);
if i = 0
then FArrayIndexValues[i].FArrayIndexValueLimit := FArrayIndexValueLimit - 2
else FArrayIndexValues[i].FArrayIndexValueLimit := FArrayIndexValueLimit - 3;
@ -2647,6 +2693,10 @@ var
FBoundHigh := PCLenToInt(PTypeResult.BoundHigh);
FLen := PCLenToInt(PTypeResult.BoundHigh) - PCLenToInt(PTypeResult.BoundLow) + 1;
if (gtcfForceArrayEval in FCreationFlags) then begin
EvaluateExpressionDynArrayGetData;
exit;
end;
if (saInternalPointer in FAttributes) then begin
if not RequireRequests([gptrEvalExprDeRef]) then exit;
@ -2678,6 +2728,77 @@ var
Result := True;
end;
procedure EvaluateExpressionRepeated;
var
ExpArray: TGDBExpressionPartArray;
s: String;
Idx: Int64;
Error: word;
begin
FProcessState := gtpsEvalExprRepeated;
if (FRepeatCount < 1) then begin
Result := True;
exit;
end;
if (FRepeatCount < 1) or (FParsedExpression.PartCount <> 1) or
not (FParsedExpression.Parts[0] is TGDBExpressionPartArray)
then begin
FRepeatCount := 0;
EvaluateExpression;
exit;
end;
if FRepeatCountEval <> nil then begin
if not FRepeatCountEval.HasExprEvaluatedAsText then begin
FRepeatCount := 0;
EvaluateExpression;
exit;
end;
FExprEvaluatedAsText := FRepeatCountEval.ExprEvaluatedAsText;
FHasExprEvaluatedAsText := True;
FreeAndNil(FRepeatCountEval);
Result := True;
exit;
end;
ExpArray := TGDBExpressionPartArray(FParsedExpression.Parts[0]);
if ExpArray.IndexCount < 1 then begin
FRepeatCount := 0;
EvaluateExpression;
exit;
end;
s := ExpArray.IndexPart[ExpArray.IndexCount - 1].GetPlainText;
if not RequireRequests([gptrEvalExpr2], Quote('('+s+')+0')) then exit;
if IsReqError(gptrEvalExpr2, False) then begin
FRepeatCount := 0;
EvaluateExpression;
exit;
end;
s := GetParsedFromResult(FReqResults[gptrEvalExpr2].Result.GdbDescription, 'value');
Val(s, Idx, Error);
if Error <> 0 then begin
FRepeatCount := 0;
EvaluateExpression;
exit;
end;
FRepeatCountEval := TGDBType.CreateForExpression(
ExpArray.GetTextToIdx(ExpArray.IndexCount-2),
FCreationFlags + [gtcfExprEvaluate, gtcfForceArrayEval],
FExprEvaluateFormat,
FRepeatCount
);
FRepeatCountEval.RepeatFirstIndex := Idx;
AddSubType(FRepeatCountEval);
end;
procedure EvaluateExpression;
begin
FProcessState := gtpsEvalExpr;
@ -2687,6 +2808,15 @@ var
exit;
end;
if (FRepeatCount > 1) and (FParsedExpression.PartCount = 1) and
(FParsedExpression.Parts[0] is TGDBExpressionPartArray) and
not(gtcfForceArrayEval in FCreationFlags)
then begin
exclude(FProccesReuestsMade, gptrEvalExpr2);
EvaluateExpressionRepeated;
exit;
end;
if saDynArray in FAttributes then begin
EvaluateExpressionDynArray;
exit;
@ -2701,6 +2831,14 @@ var
exit;
end;
if (gtcfForceArrayEval in FCreationFlags) then begin
FBoundLow := FRepeatFirstIndex;
FBoundHigh := FRepeatFirstIndex + FRepeatCount - 1;
FLen := FRepeatCount;
EvaluateExpressionDynArrayGetData;
exit;
end;
// TODO: stringFixed need to know about:
// - AutoTypeCast
@ -2738,25 +2876,25 @@ var
end;
end;
if not RequireRequests([gptrEvalExpr]) then exit;
if not IsReqError(gptrEvalExpr, False) then begin
ParseFromResult(FReqResults[gptrEvalExpr].Result.GdbDescription, 'value');
if not RequireRequests([gptrEvalExpr]) then exit;
if not IsReqError(gptrEvalExpr, False) then begin
ParseFromResult(FReqResults[gptrEvalExpr].Result.GdbDescription, 'value');
if (gtcfExprEvalStrFixed in FCreationFlags) and
(FParsedExpression <> nil) and FParsedExpression.MayNeedStringFix
then begin
if not RequireRequests([gptrEvalExpr2], FParsedExpression.TextStrFixed) then exit;
ParseFromResultForStrFixed(FReqResults[gptrEvalExpr2].Result.GdbDescription, 'value');
end;
if (gtcfExprEvalStrFixed in FCreationFlags) and
(FParsedExpression <> nil) and FParsedExpression.MayNeedStringFix
then begin
if not RequireRequests([gptrEvalExpr2], FParsedExpression.TextStrFixed) then exit;
ParseFromResultForStrFixed(FReqResults[gptrEvalExpr2].Result.GdbDescription, 'value');
end;
Result := True;
Result := True;
exit;
end;
// TODO: set Validity = error
ParseFromResult(FReqResults[gptrEvalExpr].Result.GdbDescription, 'msg');
Result := True;
end;
// TODO: set Validity = error
ParseFromResult(FReqResults[gptrEvalExpr].Result.GdbDescription, 'msg');
Result := True;
end;
{%endregion * EvaluateExpression * }
procedure ProcessInitialSimple;
@ -2984,10 +3122,10 @@ var
var
SubType, PrevSubType: TGDBType;
begin
DebugLnEnter(DBGMI_TYPE_INFO, ['>>Enter Sub-Requests']);
PrevSubType := nil;
SubType := FFirstProcessingSubType;
while SubType <> nil do begin
DebugLnEnter(DBGMI_TYPE_INFO, ['>>Enter Sub-Request']);
if SubType.ProcessExpression then begin
if PrevSubType = nil
then FFirstProcessingSubType := SubType.FNextProcessingSubType
@ -2996,10 +3134,10 @@ var
else
PrevSubType := SubType;
SubType := SubType.FNextProcessingSubType;
DebugLnExit(DBGMI_TYPE_INFO, ['>>Leave Sub-Request']);
end;
Result := FFirstProcessingSubType = nil;
DebugLnExit(DBGMI_TYPE_INFO, ['>>Leave Sub-Request']);
end;
var
@ -3011,8 +3149,7 @@ begin
FEvalRequest := nil;
FLastEvalRequest := nil;
Lines := nil;
WriteStr(s, FProcessState); // TODO dbgs
DebugLnEnter(DBGMI_TYPE_INFO, ['>>Enter: TGDBType.ProcessExpression: state = ', s, ' Expression="', FExpression, '"']);
DebugLnEnter(DBGMI_TYPE_INFO, ['>>Enter: TGDBType.ProcessExpression: ', DebugString]);
try
@ -3036,6 +3173,7 @@ begin
gtpsClassAncestor: ProcessClassAncestor;
gtpsArray: ProcessArray;
gtpsEvalExpr: EvaluateExpression;
gtpsEvalExprRepeated: EvaluateExpressionRepeated;
gtpsEvalExprArray: EvaluateExpressionArray;
gtpsEvalExprDynArray: EvaluateExpressionDynArray;
gtpsEvalExprDynArrayGetData: EvaluateExpressionDynArrayGetData;

View File

@ -39,7 +39,7 @@ unit WatchPropertyDlg;
interface
uses
Classes, Forms, StdCtrls, Extctrls, ButtonPanel, LazarusIDEStrConsts,
Classes, sysutils, Forms, StdCtrls, Extctrls, ButtonPanel, LazarusIDEStrConsts,
IDEHelpIntf, Debugger, BaseDebugManager, DebuggerStrConst;
type
@ -97,6 +97,8 @@ begin
if chkUseInstanceClass.Checked
then FWatch.EvaluateFlags := [defClassAutoCast]
else FWatch.EvaluateFlags := [];
FWatch.RepeatCount := StrToIntDef(txtRepCount.Text, 0);
FWatch.Enabled := chkEnabled.Checked;
end;
@ -124,17 +126,16 @@ begin
txtExpression.Text := AWatchExpression;
rgStyle.ItemIndex := 7;
chkUseInstanceClass.Checked := False;
txtRepCount.Text := '0';
end
else begin
txtExpression.Text := FWatch.Expression;
chkEnabled.Checked := FWatch.Enabled;
rgStyle.ItemIndex := DispFormatToStyle[FWatch.DisplayFormat];
chkUseInstanceClass.Checked := defClassAutoCast in FWatch.EvaluateFlags;
txtRepCount.Text := IntToStr(FWatch.RepeatCount);
end;
lblRepCount.Enabled := False;
txtRepCount.Enabled := False;
lblDigits.Enabled := False;
txtDigits.Enabled := False;
chkAllowFunc.Enabled := False;