~ubuntu-branches/ubuntu/saucy/lazarus/saucy

« back to all changes in this revision

Viewing changes to debugger/gdbtypeinfo.pp

  • Committer: Package Import Robot
  • Author(s): Paul Gevers, Abou Al Montacir, Bart Martens, Paul Gevers
  • Date: 2013-06-08 14:12:17 UTC
  • mfrom: (1.1.9)
  • Revision ID: package-import@ubuntu.com-20130608141217-7k0cy9id8ifcnutc
Tags: 1.0.8+dfsg-1
[ Abou Al Montacir ]
* New upstream major release and multiple maintenace release offering many
  fixes and new features marking a new milestone for the Lazarus development
  and its stability level.
  - The detailed list of changes can be found here:
    http://wiki.lazarus.freepascal.org/Lazarus_1.0_release_notes
    http://wiki.lazarus.freepascal.org/Lazarus_1.0_fixes_branch
* LCL changes:
  - LCL is now a normal package.
      + Platform independent parts of the LCL are now in the package LCLBase
      + LCL is automatically recompiled when switching the target platform,
        unless pre-compiled binaries for this target are already installed.
      + No impact on existing projects.
      + Linker options needed by LCL are no more added to projects that do
        not use the LCL package.
  - Minor changes in LCL basic classes behaviour
      + TCustomForm.Create raises an exception if a form resource is not
        found.
      + TNotebook and TPage: a new implementation of these classes was added.
      + TDBNavigator: It is now possible to have focusable buttons by setting
        Options = [navFocusableButtons] and TabStop = True, useful for
        accessibility and for devices with neither mouse nor touch screen.
      + Names of TControlBorderSpacing.GetSideSpace and GetSpace were swapped
        and are now consistent. GetSideSpace = Around + GetSpace.
      + TForm.WindowState=wsFullscreen was added
      + TCanvas.TextFitInfo was added to calculate how many characters will
        fit into a specified Width. Useful for word-wrapping calculations.
      + TControl.GetColorResolvingParent and
        TControl.GetRGBColorResolvingParent were added, simplifying the work
        to obtain the final color of the control while resolving clDefault
        and the ParentColor.
      + LCLIntf.GetTextExtentExPoint now has a good default implementation
        which works in any platform not providing a specific implementation.
        However, Widgetset specific implementation is better, when available.
      + TTabControl was reorganized. Now it has the correct class hierarchy
        and inherits from TCustomTabControl as it should.
  - New unit in the LCL:
      + lazdialogs.pas: adds non-native versions of various native dialogs,
        for example TLazOpenDialog, TLazSaveDialog, TLazSelectDirectoryDialog.
        It is used by widgetsets which either do not have a native dialog, or
        do not wish to use it because it is limited. These dialogs can also be
        used by user applications directly.
      + lazdeviceapis.pas: offers an interface to more hardware devices such
        as the accelerometer, GPS, etc. See LazDeviceAPIs
      + lazcanvas.pas: provides a TFPImageCanvas descendent implementing
        drawing in a LCL-compatible way, but 100% in Pascal.
      + lazregions.pas. LazRegions is a wholly Pascal implementation of
        regions for canvas clipping, event clipping, finding in which control
        of a region tree one an event should reach, for drawing polygons, etc.
      + customdrawncontrols.pas, customdrawndrawers.pas,
        customdrawn_common.pas, customdrawn_android.pas and
        customdrawn_winxp.pas: are the Lazarus Custom Drawn Controls -controls
        which imitate the standard LCL ones, but with the difference that they
        are non-native and support skinning.
  - New APIs added to the LCL to improve support of accessibility software
    such as screen readers.
* IDE changes:
  - Many improvments.
  - The detailed list of changes can be found here:
    http://wiki.lazarus.freepascal.org/New_IDE_features_since#v1.0_.282012-08-29.29
    http://wiki.lazarus.freepascal.org/Lazarus_1.0_release_notes#IDE_Changes
* Debugger / Editor changes:
  - Added pascal sources and breakpoints to the disassembler
  - Added threads dialog.
* Components changes:
  - TAChart: many fixes and new features
  - CodeTool: support Delphi style generics and new syntax extensions.
  - AggPas: removed to honor free licencing. (Closes: Bug#708695)
[Bart Martens]
* New debian/watch file fixing issues with upstream RC release.
[Abou Al Montacir]
* Avoid changing files in .pc hidden directory, these are used by quilt for
  internal purpose and could lead to surprises during build.
[Paul Gevers]
* Updated get-orig-source target and it compinion script orig-tar.sh so that they
  repack the source file, allowing bug 708695 to be fixed.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
{ $Id: gdbtypeinfo.pp 29178 2011-01-23 19:06:01Z vincents $ }
 
1
{ $Id: gdbtypeinfo.pp 39506 2012-12-10 20:10:59Z maxim $ }
2
2
{                        ----------------------------------------------
3
3
                            GDBTypeInfo.pp  -  Debugger helper class 
4
4
                         ----------------------------------------------
5
5
 
6
6
 @created(Wed Mar 29th WET 2003)
7
 
 @lastmod($Date: 2011-01-23 19:06:01 +0000 (Sun, 23 Jan 2011) $)
 
7
 @lastmod($Date: 2012-12-10 21:10:59 +0100 (Mon, 10 Dec 2012) $)
8
8
 @author(Marc Weustink <marc@@dommelstein.net>)
9
9
 
10
10
 This unit contains a helper class for decoding PType output.
34
34
interface
35
35
 
36
36
uses
37
 
  Classes, SysUtils, Debugger, LclProc, DebugUtils;
 
37
  Classes, SysUtils, Debugger, LclProc, math, LazLoggerBase, DebugUtils, GDBMIMiscClasses;
38
38
 
39
39
(*
40
40
  ptype = {
50
50
    [ name = "..." ]
51
51
    [ type = "..." ]
52
52
 
53
 
  Examples: (tested with fpc 2.4.2 and 2.5.1 (Jan 2011) / gdb 7.0, gdb 7.2
54
 
  (excluding the '~"type = '  and the '\n"')
55
 
 
56
 
  * procedure x(ArgTFoo: TFoo; var VArgTFoo: TFoo); // TFoo = class end;
57
 
  * procedure x(ArgPFoo: PFoo; var VArgPFoo: PFoo); // PFoo = ^TFoo;
58
 
 
59
 
  "WhatIs" Results:     Normal                          Param-by-ref
60
 
                 Stabs    Dwarf        |               Stabs    Dwarf
61
 
    ArgTFoo      TFOO     TFOO         |  VArgTFoo     TFOO     &TFOO
62
 
    @ArgTFoo     PFOO     ^TFOO        |  @VArgTFoo    PFOO     ^&TFOO     ## whatis @ArgTFoo  may be ^TFoo under Stabs if no named type PFoo exists
63
 
    ArgPFoo      PFOO     PFOO         |  VArgPFoo     PFOO     &PFOO
64
 
    @ArgPFoo     PPFOO    ^PFOO        |  @VArgPFoo    PPFOO    ^&PFOO     ## whatis @ArgPFoo  may be ^PFoo under Stabs if no named type PPFoo exists
65
 
 
66
 
                 Stabs    Dwarf
67
 
    TFoo         TFOO     ^TFOO = class
68
 
    PFoo         PFOO     ^TFOO
69
 
 
70
 
  "PType" Results:
71
 
    ptype Arg<YYY>       ~"type = <???> = class : public TOBJECT \n"   ## followed by lines of fields (exlude inherited)
72
 
                       Normal                           Param-by-ref
73
 
                 Stabs    Dwarf        |               Stabs    Dwarf
74
 
    ArgTFoo      ^TFOO    ^TFOO        |  VArgTFoo     ^TFOO    &TFOO
75
 
    @ArgTFoo     ^TFOO    ^TFOO        |  @VArgTFoo    ^TFOO    ^&TFOO
76
 
    ArgPFoo      ^TFOO    ^TFOO        |  VArgPFoo     ^TFOO    &TFOO
77
 
    @ArgPFoo      ^TFOO   ^TFOO        |  @VArgPFoo    ^TFOO    ^&TFOO
78
 
 
79
 
                 Stabs    Dwarf
80
 
    TFoo         TFOO     ^TFOO
81
 
    PFoo         ^TFOO    ^TFOO
82
 
 
83
 
    ==> "ptype SomeVariable" does not differ between TFoo and PFoo
84
 
    ==> dwarf ptype is the same for TFoo and PFoo (whatis can tell the diff)
85
 
 
86
 
  * procedure x(ArgEnum: TEnum); // TEnum = (One, Two, Three);
87
 
  * procedure x(ArgEnumSet: TEnumSet; var VArgEnumSet: TEnumSet); // TEnumSet = set of TEnum;
88
 
  * procedure x(ArgSet: TSet; var VArgSet: TSet); // TSet = Set of (Alpha, Beta, Gamma);
89
 
  * var VarEnumA: (e1,e2,e3); VarEnumSetA: set of TEnum; VarSetA: Set of (s1,s2,s3);
90
 
 
91
 
  "WhatIs" Results (| marks a new line / gdb starts a new line with ~"):
92
 
                 Stabs                 Dwarf                     Dwarf without -godwarfset
93
 
    ArgEnumSet   TENUMSET              TENUMSET                  TENUMSET
94
 
    VArgEnumSet  TENUMSET              &TENUMSET                 &TENUMSET
95
 
    ArgSet       TSET                  TSET                      TSET
96
 
    VArgSet      TSET                  &TSET                     &TSET
97
 
    VarEnumSetA  set of TENUM          set of |ONE..THREE        <invalid unnamed pascal type code 8>
98
 
    VarSetA      set of  = (...)       set of |S1..S3            <invalid unnamed pascal type code 8>
99
 
 
100
 
    TEnumSet     TENUMSET              set of |ONE..THREE        TENUMSET
101
 
    TSet         TSET                  set of |ALPHA..GAMMA      TSET
102
 
 
103
 
    ArgEnum      TENUM                        ## same for stabs (both)
104
 
    VarEnumA      = (...)                     ## same for stabs (both)
105
 
    TEnum        TENUN                        ## same for stabs (both)
106
 
 
107
 
  "PType" Results:
108
 
                 Stabs                            Dwarf                      Dwarf without -godwarfset
109
 
 
110
 
    ArgEnumSet   set of TENUM                     set of |ONE..THREE         TENUMSET
111
 
    VArgEnumSet  set of TENUM                     &set of |ONE..THREE        &TENUMSET
112
 
    ArgSet       set of  = (ALPHA, BETA, GAMMA)   set of |ALPHA..GAMMA       TSET
113
 
    VArgSet      set of  = (ALPHA, BETA, GAMMA)   &set of |ALPHA..GAMMA      &TSET
114
 
    VarEnumSetA  set of TENUM                     set of |ONE..THREE         <invalid unnamed pascal type code 8>
115
 
    VarSetA      set of  = (S1, S2, S3)           set of |S1..S3             <invalid unnamed pascal type code 8>
116
 
 
117
 
    TEnumSet     set of TENUM                     set of |ONE..THREE         TENUMSET
118
 
    TSet         set of  = (ALPHA, BETA, GAMMA)   set of |ALPHA..GAMMA       TSET
119
 
 
120
 
    ArgEnum      TENUM  = (ONE, TWO, THREE)      ## same for stabs (both)
121
 
    VarEnumA      = (E1, E2, E3)                 ## same for stabs (both)
122
 
    TEnum        TENUM  = (ONE, TWO, THREE)      ## same for stabs (both)
123
 
 
124
 
      ## Alternative new lines:  set of ONE|..THREE|      set of S1|..S3|
125
 
      ## All results can be prefixed by ^, for unamed pointertypes (^& for var param)
126
 
 
127
 
 
128
 
 
129
 
  TODO: functions ? Stabs seem to always add pointer; dwarf does not?
 
53
 
 
54
  For example results, comparision between similar types, different GDB versions
 
55
  or stabs vs dwarf, see the folder "test/gdb responses/"
130
56
 
131
57
*)
132
58
type
135
61
    (ptprfParamByRef,
136
62
     ptprfPointer,
137
63
     ptprfNoStructure,     // for Class or Record: no full class declaration, type ends after class keyword; DWARF "whatis TFoo"
138
 
                         // includes "record {...}"
139
 
     ptprfEmpty
 
64
                           // includes "record {...}"
 
65
     ptprfDynArray,
 
66
     ptprfNoBounds,        // no bounds for array found
 
67
     ptprfEmpty,
 
68
     ptprfDeclarationInBrackets  // e.g ^(array ...) / "&^()" is/are not included in BaseDeclaration
140
69
    );
141
70
  TGDBPTypeResultFlags = set of TGDBPTypeResultFlag;
142
71
  TGDBPTypeResultKind =
143
 
    (ptprkError, ptprkSimple, ptprkClass, ptprkRecord,
 
72
    (ptprkNotEvaluated, ptprkError, ptprkSimple, ptprkClass, ptprkRecord,
144
73
     ptprkEnum, ptprkSet, ptprkArray, ptprkProcedure, ptprkFunction);
145
74
 
146
75
  TGDBPTypeResult = record
148
77
    Flags: TGDBPTypeResultFlags;
149
78
    Kind: TGDBPTypeResultKind;
150
79
    Name, BaseName: TPCharWithLen; // BaseName is without ^&
151
 
    Declaration: TPCharWithLen;
 
80
    BoundLow, BoundHigh: TPCharWithLen;
 
81
    Declaration, BaseDeclaration: TPCharWithLen; // BaseDeclaration only for Array and Set types, see note on ptprfDeclarationInBrackets
 
82
    PointerCount: Integer;
 
83
    // type of array entry, or set-enum
 
84
    SubName, BaseSubName: TPCharWithLen;
 
85
    SubFlags: TGDBPTypeResultFlags;
 
86
    SubKind: TGDBPTypeResultKind;
 
87
    // multi-dim array
 
88
    NestArrayCount: Integer;
 
89
    NestArray: array of record  // reverse order, last entry is first nest level
 
90
      Flags: TGDBPTypeResultFlags;
 
91
      BoundLow, BoundHigh: TPCharWithLen;
 
92
      PointerCount: Integer;
 
93
    end;
152
94
  end;
153
95
 
 
96
  TGDBCommandRequestType = (gcrtPType, gcrtEvalExpr);
 
97
 
154
98
  PGDBPTypeRequest = ^TGDBPTypeRequest;
155
99
  TGDBPTypeRequest = record
156
100
    Request: string;
 
101
    ReqType: TGDBCommandRequestType;
157
102
    Result: TGDBPTypeResult;
158
103
    Error: string;
159
104
    Next: PGDBPTypeRequest;
160
105
  end;
161
106
 
 
107
 
 
108
  (* List:      "ACount", "+", "1"
 
109
     Array:     "Item[1][2]"
 
110
     Cast/Call: "Foo(Bar)"
 
111
  *)
 
112
 
 
113
  { TGDBExpressionPart }
 
114
 
 
115
  TGDBExpressionPart = class
 
116
  protected
 
117
    FText: TPCharWithLen;
 
118
    function GetParts(Index: Integer): TGDBExpressionPart; virtual;
 
119
    function GetTextFixed(AStringFixed: Boolean): String; virtual;
 
120
    function GetText: String;
 
121
    function GetTextStrFixed: String;
 
122
    function ParseExpression(AText: PChar; ATextLen: Integer): TGDBExpressionPart;
 
123
    procedure Init; virtual;
 
124
    procedure InitReq(var AReqPtr: PGDBPTypeRequest; var AReqVar: TGDBPTypeRequest;
 
125
                      AReqText: String; AType: TGDBCommandRequestType = gcrtPType);
 
126
  public
 
127
    function NeedValidation(var AReqPtr: PGDBPTypeRequest): Boolean; virtual;
 
128
    function MayNeedStringFix: Boolean; virtual;
 
129
    function MayNeedTypeCastFix: Boolean; virtual;
 
130
  public
 
131
    constructor Create;
 
132
    function IsNamedOperator: Boolean;
 
133
    function PartCount: Integer; virtual;
 
134
    property Parts[Index: Integer]: TGDBExpressionPart read GetParts;
 
135
    property Text: String read GetText;
 
136
    property TextStrFixed: String read GetTextStrFixed;
 
137
  end;
 
138
 
 
139
  { TGDBExpression }
 
140
 
 
141
  TGDBExpression = class(TGDBExpressionPart)
 
142
  private
 
143
    FTextStr: String;
 
144
  protected
 
145
    FExpressionPart: TGDBExpressionPart;
 
146
    function GetTextFixed(AStringFixed: Boolean): String; override;
 
147
    function GetParts(Index: Integer): TGDBExpressionPart; override;
 
148
  public
 
149
    constructor CreateSimple(AText: PChar; ATextLen: Integer);
 
150
    constructor Create(AText: PChar; ATextLen: Integer); virtual; overload;
 
151
    constructor Create(ATextStr: String); overload;
 
152
    destructor Destroy; override;
 
153
    function PartCount: Integer; override;
 
154
    function IsCommaSeparated: Boolean;
 
155
  end;
 
156
 
 
157
  { TGDBExpressionPartBracketed }
 
158
 
 
159
  TGDBExpressionPartBracketed = class(TGDBExpression)
 
160
  protected
 
161
    function GetTextFixed(AStringFixed: Boolean): String; override;
 
162
    function GetPlainText: String;
 
163
  public
 
164
    constructor Create(AText: PChar; ATextLen: Integer); override; overload;
 
165
  end;
 
166
 
 
167
  { TGDBExpressionPartListBase }
 
168
 
 
169
  TGDBExpressionPartListBase = class(TGDBExpressionPart)
 
170
  private
 
171
    FList: TFPList;
 
172
  protected
 
173
    function GetParts(Index: Integer): TGDBExpressionPart; override;
 
174
    function GetTextFixed(AStringFixed: Boolean): String; override;
 
175
  public
 
176
    constructor Create;
 
177
    destructor Destroy; override;
 
178
    procedure Clear;
 
179
    procedure ClearShared;
 
180
    function  Add(APart: TGDBExpressionPart):Integer;
 
181
    procedure Insert(AIndex: Integer; APart: TGDBExpressionPart);
 
182
    procedure Delete(AIndex: Integer);
 
183
    function  PartCount: Integer; override;
 
184
  end;
 
185
 
 
186
  TGDBExpressionPartList = class(TGDBExpressionPartListBase)
 
187
  public
 
188
    function AddList(APartList: TGDBExpressionPartList):Integer;
 
189
  end;
 
190
 
 
191
  { TGDBExpressionPartCommaList }
 
192
 
 
193
  TGDBExpressionPartCommaList = class(TGDBExpressionPartList)
 
194
  protected
 
195
    function GetTextFixed(AStringFixed: Boolean): String; override;
 
196
  end;
 
197
 
 
198
  { TGDBExpressionPartArrayIdx }
 
199
 
 
200
  TGDBExpressionPartArrayIdx = class(TGDBExpressionPartBracketed)
 
201
  private
 
202
    FArrayPTypeNestIdx: integer;
 
203
    FArrayPTypePointerIdx: integer;
 
204
    FPTypeIndexReq: TGDBPTypeRequest;
 
205
    FVarParam: Boolean;
 
206
    FPTypeReq: TGDBPTypeRequest;
 
207
    FPTypeDeRefReq: TGDBPTypeRequest;
 
208
    function GetArrayPTypeIsDeRef: boolean;
 
209
    function GetArrayPTypeIsPointer: boolean;
 
210
    function GetArrayPTypeResult: TGDBPTypeResult;
 
211
  protected
 
212
    procedure Init; override;
 
213
    procedure InitReq(var AReqPtr: PGDBPTypeRequest; AReqText: String); overload;
 
214
    procedure InitDeRefReq(var AReqPtr: PGDBPTypeRequest; AReqText: String);
 
215
    procedure InitIndexReq(var AReqPtr: PGDBPTypeRequest);
 
216
    function GetTextFixed(AStringFixed: Boolean): String; override;
 
217
    property VarParam: Boolean read FVarParam write FVarParam;
 
218
    property PTypeReq: TGDBPTypeRequest read FPTypeReq write FPTypeReq;
 
219
    property PTypeDeRefReq: TGDBPTypeRequest read FPTypeDeRefReq write FPTypeDeRefReq;
 
220
    property PTypeIndexReq: TGDBPTypeRequest read FPTypeIndexReq write FPTypeIndexReq;
 
221
    property ArrayPTypeResult: TGDBPTypeResult read GetArrayPTypeResult;
 
222
    property ArrayPTypeIsDeRef: boolean read GetArrayPTypeIsDeRef;
 
223
    property ArrayPTypeIsPointer: boolean read GetArrayPTypeIsPointer;
 
224
    property ArrayPTypeNestIdx: integer read FArrayPTypeNestIdx write FArrayPTypeNestIdx;
 
225
    property ArrayPTypePointerIdx: integer read FArrayPTypePointerIdx write FArrayPTypePointerIdx;
 
226
    // for comma separated
 
227
    function CreateExpressionForSubIndex(AIndex: Integer): TGDBExpressionPartArrayIdx;
 
228
  end;
 
229
 
 
230
  { TGDBExpressionPartArray }
 
231
 
 
232
  TGDBExpressionPartArray = class(TGDBExpressionPartListBase)
 
233
  private
 
234
    FNeedTypeCast: Boolean;
 
235
    FMaybeString: Boolean;
 
236
    function GetIndexParts(Index: Integer): TGDBExpressionPartArrayIdx;
 
237
  protected
 
238
    function GetTextFixed(AStringFixed: Boolean): String; override;
 
239
    function GetTextToIdx(AIdx: Integer; AStrFixed: Boolean = False): String;
 
240
    function IndexCount: Integer;
 
241
    property IndexPart[Index: Integer]: TGDBExpressionPartArrayIdx read GetIndexParts;
 
242
  public
 
243
    constructor Create(ALeadExpresion: TGDBExpressionPart);
 
244
    function AddIndex(APart: TGDBExpressionPartArrayIdx):Integer;
 
245
    function NeedValidation(var AReqPtr: PGDBPTypeRequest): Boolean; override;
 
246
    function MayNeedStringFix: Boolean; override;
 
247
    property NeedTypeCast: Boolean read FNeedTypeCast write FNeedTypeCast;
 
248
  end;
 
249
 
 
250
  { TGDBExpressionPartCastCall }
 
251
  TTypeCastFixFlag = (tcfUnknown, tcfEvalNeeded, tcfNoFixNeeded, tcfFixNeeded);
 
252
 
 
253
  TGDBExpressionPartCastCall = class(TGDBExpressionPartListBase)
 
254
  private
 
255
    FIsFunction: Boolean;
 
256
    FIsTypeCast: Boolean;
 
257
    FPTypeReq: TGDBPTypeRequest;
 
258
    FTypeCastFixFlag: TTypeCastFixFlag;
 
259
  protected
 
260
    procedure Init; override;
 
261
    function GetTextFixed(AStringFixed: Boolean): String; override;
 
262
    property PTypeReq: TGDBPTypeRequest read FPTypeReq write FPTypeReq;
 
263
  public
 
264
    constructor Create(ALeadExpresion: TGDBExpressionPart);
 
265
    function AddBrackets(APart: TGDBExpressionPart):Integer;
 
266
    function NeedValidation(var AReqPtr: PGDBPTypeRequest): Boolean; override;
 
267
    function MayNeedTypeCastFix: Boolean; override;
 
268
    property IsFunction: Boolean read FIsFunction;
 
269
    property IsTypeCast: Boolean read FIsTypeCast;
 
270
  end;
 
271
 
 
272
 
 
273
  { TGDBPTypeRequestCacheEntry }
 
274
 
 
275
  TGDBPTypeRequestCacheEntry = class
 
276
  protected
 
277
    FRequest: TGDBPTypeRequest;
 
278
    FStackFrame: Integer;
 
279
    FThreadId: Integer;
 
280
  public
 
281
    property ThreadId: Integer read FThreadId;
 
282
    property StackFrame: Integer read FStackFrame;
 
283
    property Request: TGDBPTypeRequest read FRequest;
 
284
  end;
 
285
 
 
286
  TGDBPTypeRequestCache = class
 
287
  private
 
288
    FList: TFPList;
 
289
    function GetRequest(Index: Integer): TGDBPTypeRequest;
 
290
  public
 
291
    constructor Create;
 
292
    destructor Destroy; override;
 
293
    procedure Clear;
 
294
    function IndexOf(AThreadId, AStackFrame: Integer; ARequest: TGDBPTypeRequest): Integer;
 
295
    procedure Add(AThreadId, AStackFrame: Integer; ARequest: TGDBPTypeRequest);
 
296
    property Request[Index: Integer]: TGDBPTypeRequest read GetRequest;
 
297
  end;
 
298
 
162
299
  { TGDBTypes }
163
300
 
164
301
  TGDBTypes = class(TDBGTypes)
168
305
 
169
306
  { TGDBType }
170
307
 
 
308
  TGDBTypeCreationFlag = (gtcfClassIsPointer,
 
309
                          gtcfFullTypeInfo,
 
310
                          gtcfSkipTypeName,
 
311
                          gtcfExprIsType,
 
312
                          gtcfExprEvaluate,
 
313
                          gtcfExprEvalStrFixed,      // Evaluate with string fix, if needed; only if gtcfExprEvaluate is set
 
314
                          gtcfAutoCastClass          // Find real class of instance, and use, instead of declared class of variable
 
315
                         );
 
316
  TGDBTypeCreationFlags = set of TGDBTypeCreationFlag;
 
317
 
171
318
  TGDBTypeProcessState =
172
 
    (gtpsInitial,
173
 
     gtpsInitialPType,
174
 
     gtpsInitialPType2, gtpsInitialPType3, // with "whaties Expr" // with "whaties Expr" and "ptype <whaties Expr>"
 
319
    (gtpsInitial, gtpsInitialSimple,
175
320
     gtpsSimplePointer,
176
 
     gtpsClassWhatIs, gtpsClassNameWhatIs, gtpsClassNamePType
177
 
    );
 
321
     gtpsClass, gtpsClassAutoCast, gtpsClassPointer, gtpsFinishProcessClass, gtpsClassAncestor,
 
322
     gtpsArray,
 
323
     gtpsEvalExpr, gtpsEvalExprArray, gtpsEvalExprDynArray, gtpsEvalExprDynArrayGetData,
 
324
     gtpsFinished
 
325
    );
 
326
 
 
327
  TGDBTypeProcessRequest =
 
328
    (gptrPTypeExpr, gptrWhatisExpr, gptrPTypeOfWhatis,
 
329
     gptrPTypeExprDeRef, gptrPTypeExprDeDeRef,  // "Foo^", "Foo^^"  for Foo=Object, or &Object
 
330
     gptrEvalExpr, gptrEvalExprDeRef, gptrEvalExprCast,
 
331
     gptrEvalExpr2, gptrEvalExprDeRef2, gptrEvalExprCast2, // used by MaybeString
 
332
     gptrPtypeCustomFixCast, gptrPtypeCustomAutoCast, gptrPtypeCustomAutoCast2,
 
333
     gptrInstanceClassName,
 
334
     gptrPtypeCustomEval
 
335
    );
 
336
  TGDBTypeProcessRequests = set of TGDBTypeProcessRequest;
178
337
 
179
338
  TGDBType = class(TDBGType)
180
339
  private
181
340
    FInternalTypeName: string;
182
341
  private
 
342
    FEvalStarted: Boolean;
 
343
    FExpression, FOrigExpression: string;
 
344
    FHasStringExprEvaluatedAsText: Boolean;
 
345
    FCreationFlags: TGDBTypeCreationFlags;
 
346
 
 
347
    // Value-Eval
 
348
    FExprEvaluatedAsText: String;
 
349
    FHasExprEvaluatedAsText: Boolean;
 
350
    FExprEvaluateFormat: TWatchDisplayFormat;
 
351
 
 
352
    // Sub-Types (FNext is managed by creator / linked list)
 
353
    FFirstProcessingSubType, FNextProcessingSubType: TGDBType;
 
354
    FStringExprEvaluatedAsText: String;
 
355
    FTypeInfoAncestor: TGDBType;
 
356
 
 
357
    FArrayIndexValues: Array of TGDBType;
 
358
    FArrayIndexValueLimit: Integer;
 
359
 
 
360
    // Gdb-Requests
183
361
    FEvalError: boolean;
184
 
    FEvalRequest: PGDBPTypeRequest;
185
 
    FExpression: string;
186
 
    FClassIsPointer: Boolean;
 
362
    FEvalRequest, FLastEvalRequest: PGDBPTypeRequest;
 
363
 
187
364
    FProcessState: TGDBTypeProcessState;
188
 
    FPTypeExprReq, FWhatIsExprReq: TGDBPTypeRequest;
189
 
    FExtraReq: TGDBPTypeRequest;
 
365
    FProccesReuestsMade: TGDBTypeProcessRequests;
 
366
    FReqResults: Array [TGDBTypeProcessRequest] of TGDBPTypeRequest;
 
367
 
 
368
    FParsedExpression: TGDBExpression;
 
369
 
 
370
    FHasAutoTypeCastFix: Boolean;
 
371
    FAutoTypeCastName: String;
 
372
 
190
373
    procedure AddTypeReq(var AReq :TGDBPTypeRequest; const ACmd: string = '');
 
374
    procedure AddSubType(ASubType :TGDBType);
 
375
    function GetIsFinished: Boolean;
 
376
    function RequireRequests(ARequired: TGDBTypeProcessRequests; ACustomData: String = ''): Boolean;
 
377
    function IsReqError(AReqType: TGDBTypeProcessRequest; CheckResKind: Boolean = True): Boolean;
 
378
  protected
 
379
    procedure Init; override;
191
380
  public
192
381
    constructor CreateForExpression(const AnExpression: string;
193
 
                                    const AClassIsPointer: Boolean = False);
 
382
                                    const AFlags: TGDBTypeCreationFlags;
 
383
                                    AFormat: TWatchDisplayFormat = wdfDefault);
 
384
    destructor Destroy; override;
194
385
    function ProcessExpression: Boolean;
195
386
    property EvalRequest: PGDBPTypeRequest read FEvalRequest;
196
387
    property EvalError: boolean read FEvalError;
 
388
    property IsFinished: Boolean read GetIsFinished;
 
389
 
 
390
    property HasExprEvaluatedAsText: Boolean read FHasExprEvaluatedAsText;
 
391
    property ExprEvaluatedAsText: String read FExprEvaluatedAsText;
 
392
 
 
393
    // Expression with index fixed by -1 for string access
 
394
    property HasStringExprEvaluatedAsText: Boolean read FHasStringExprEvaluatedAsText;
 
395
    property StringExprEvaluatedAsText: String read FStringExprEvaluatedAsText;
197
396
  public
198
397
    // InternalTypeName: include ^ for TObject, if needed
199
398
    property InternalTypeName: string read FInternalTypeName;
203
402
function CreatePTypeValueList(AResultValues: String): TStringList;
204
403
function ParseTypeFromGdb(const ATypeText: string): TGDBPTypeResult;
205
404
 
 
405
function dbgs(AFlag: TGDBPTypeResultFlag): string; overload;
 
406
function dbgs(AFlags: TGDBPTypeResultFlags): string; overload;
 
407
function dbgs(AKind: TGDBPTypeResultKind): string; overload;
 
408
function dbgs(AReqType: TGDBCommandRequestType): string; overload;
 
409
function dbgs(AReq: TGDBPTypeRequest): string; overload;
 
410
 
206
411
implementation
207
412
 
208
 
(*
209
 
function GetPart(const ASkipTo, AnEnd: array of String; var ASource: String): String;
 
413
const
 
414
  GdbCmdPType = 'ptype ';
 
415
  GdbCmdWhatIs = 'whatis ';
 
416
  GdbCmdEvaluate = '-data-evaluate-expression ';
210
417
var
211
 
  n, i, idx, SkipLen: Integer;
212
 
begin
213
 
  idx := 0;
214
 
  SkipLen := 0;
215
 
  if High(ASkipTo) <> -1
216
 
  then begin
217
 
    for n := Low(ASkipTo) to High(ASkipTo) do
218
 
    begin
219
 
      if ASkipTo[n] <> ''
220
 
      then begin
221
 
        i := Pos(ASkipTo[n], ASource);
222
 
        if (i > 0) and ((idx = 0) or (i < idx))
223
 
        then begin
224
 
          idx := i;
225
 
          SkipLen := Length(ASkipTo[n]);
226
 
        end;
227
 
      end;
228
 
    end;
229
 
    if idx = 0
230
 
    then begin
231
 
      Result := '';
232
 
      Exit;
233
 
    end;
234
 
    Delete(ASource, 1, idx + SkipLen - 1);
235
 
  end;
236
 
 
237
 
  idx := 0;
238
 
  for n := Low(AnEnd) to High(AnEnd) do
239
 
  begin
240
 
    if AnEnd[n] <> ''
241
 
    then begin
242
 
      i := Pos(AnEnd[n], ASource);
243
 
      if (i > 0) and ((idx = 0) or (i < idx))
244
 
      then idx := i;
245
 
    end;
246
 
  end;
247
 
 
248
 
  if idx = 0
249
 
  then begin
250
 
    Result := ASource;
251
 
    ASource := '';
252
 
  end
253
 
  else begin
254
 
    Result := Copy(ASource, 1, idx - 1);
255
 
    Delete(ASource, 1, idx - 1);
256
 
  end;
257
 
end;
258
 
*)
 
418
  DBGMI_TYPE_INFO: PLazLoggerLogGroup;
259
419
 
260
420
function CreatePTypeValueList(AResultValues: String): TStringList;
261
421
var
383
543
  end;
384
544
end;
385
545
 
386
 
function ParseTypeFromGdb(const ATypeText: string): TGDBPTypeResult;
 
546
function ParseTypeFromGdb(const ATypeText: PChar; const ATypeTextLen: Integer): TGDBPTypeResult;
387
547
var
388
 
  i, StartIdx, EndIdx: Integer;
389
 
  CurPtr, HelpPtr, HelpPtr2, EndPtr, DeclPtr: PChar;
 
548
  i: Integer;
 
549
  CurPtr, LineEndPtr, EndPtr, BaseDeclPtr, DeclPtr, DeclEndPtr: PChar;
 
550
  HelpPtr, HelpPtr2: PChar;
 
551
  SubRes: TGDBPTypeResult;
390
552
 
391
553
  procedure SkipSpaces(var p: PChar); inline;
392
554
  begin
399
561
    // Might be: "set of ", "class", "record =", "array [", '<invalid unnamed"...,
400
562
    case CurPtr^ of
401
563
      's', 'S': begin
402
 
          if (EndPtr - CurPtr >= 6 )
 
564
          if (LineEndPtr - CurPtr >= 6 )
403
565
          and  (UpperCase(copy(CurPtr, 1, 7)) = 'SET OF ')
404
566
          then
405
567
            Result := ptprkSet;
406
568
        end;
407
569
      'r', 'R': begin
408
 
          if (EndPtr - CurPtr >= 6 )
 
570
          if (LineEndPtr - CurPtr >= 5 )
409
571
          and (UpperCase(copy(CurPtr, 1, 6)) = 'RECORD')
410
 
          and ((CurPtr+6)^ in [' ', ')', #13])
 
572
          and ((CurPtr+6)^ in [' ', ')', #13, #0])
411
573
          then
412
574
            Result := ptprkRecord;
413
575
        end;
414
576
      'c', 'C': begin
415
 
          if (EndPtr - CurPtr >= 5 )
 
577
          if (LineEndPtr - CurPtr >= 4 )
416
578
          and (UpperCase(copy(CurPtr, 1, 5)) = 'CLASS')
417
 
          and ((CurPtr+5)^ in [' ', ')', #13])
 
579
          and ((CurPtr+5)^ in [' ', ')', #13, #0])
418
580
          then
419
581
            Result := ptprkClass;
420
582
        end;
421
583
      'a', 'A': begin
422
 
          if (EndPtr - CurPtr >= 5 )
 
584
          if (LineEndPtr - CurPtr >= 5 )
423
585
          and (UpperCase(copy(CurPtr, 1, 6)) = 'ARRAY ')
424
586
          then
425
587
            Result := ptprkArray;
426
588
        end;
427
589
      '<': begin
428
 
          if (EndPtr - CurPtr >= 35 )
 
590
          if (LineEndPtr - CurPtr >= 35 )
429
591
          and (copy(CurPtr, 1, 36) = '<invalid unnamed pascal type code 8>')
430
592
          then
431
593
            Result := ptprkSet;
432
594
        end;
433
595
      'p', 'P': begin
434
 
          if (EndPtr - CurPtr >= 9 )
 
596
          if (LineEndPtr - CurPtr >= 8 )
435
597
          and (UpperCase(copy(CurPtr, 1, 9)) = 'PROCEDURE')
436
 
          and ((CurPtr+9)^ in [' ', '(', ')', #13])
 
598
          and ((CurPtr+9)^ in [' ', '(', ')', #13, #0])
437
599
          then
438
600
            Result := ptprkProcedure;
439
601
        end;
440
602
      'f', 'F': begin
441
 
          if (EndPtr - CurPtr >= 8 )
 
603
          if (LineEndPtr - CurPtr >= 7 )
442
604
          and (UpperCase(copy(CurPtr, 1, 8)) = 'FUNCTION')
443
 
          and ((CurPtr+8)^ in [' ', '(', ')', #13])
 
605
          and ((CurPtr+8)^ in [' ', '(', ')', #13, #0])
444
606
          then
445
607
            Result := ptprkFunction;
446
608
        end;
457
619
 
458
620
    p := CurPtr;
459
621
    while not(p^ in [')', #0]) do inc(p);
460
 
    if (p <= EndPtr) and (p^ = ')') then
 
622
    if (p <= LineEndPtr) and (p^ = ')') then
461
623
      Result := p - CurPtr + 1;
462
624
  end;
463
625
 
 
626
  procedure SetPCharLen(var ATarget: TPCharWithLen; AStartPtr, AEndPtr: PChar);
 
627
  begin
 
628
    ATarget.Ptr := AStartPtr;
 
629
    ATarget.Len := AEndPtr - AStartPtr + 1;
 
630
  end;
 
631
 
464
632
begin
465
 
  Result.GdbDescription := ATypeText;
 
633
  try
466
634
  Result.Flags := [];
467
635
  Result.Kind := ptprkError;
468
636
  Result.Name.Ptr := nil;
471
639
  Result.BaseName.Len := 0;
472
640
  Result.Declaration.Ptr := nil;
473
641
  Result.Declaration.Len := 0;
474
 
  If ATypeText = '' then exit;
475
 
 
476
 
(*  // Clean the gdb outpu, remove   ~"...."; replace \n by #13
477
 
  if (length(ATypeText) >= 2) and (ATypeText[1] = '~') and (ATypeText[2] = '"') then
478
 
    UniqueString(Result.GdbDescription);
479
 
  CurPtr := @Result.GdbDescription[1];
480
 
  EndPtr := CurPtr;
481
 
  while (EndPtr^ <> #0) do begin
482
 
    if (EndPtr^ = '~') and ((EndPtr+1)^ = '"') then begin
483
 
      inc(EndPtr, 2);
484
 
      while not (EndPtr^ in [#0..#31]) do begin
485
 
        if (EndPtr^ = '\') then begin
486
 
          inc(EndPtr);
487
 
          if (EndPtr^ = 'n')
488
 
          then CurPtr^ := #13 // internal marker only, no need for OS specific
489
 
          else CurPtr^ := EndPtr^;
490
 
        end
491
 
        else
492
 
          CurPtr^ := EndPtr^;
493
 
        inc(EndPtr);
494
 
        inc(CurPtr);
495
 
      end;
496
 
      dec(CurPtr);
497
 
      if CurPtr^ <> '"' then begin
498
 
        // something wrong
499
 
        debugln('** WARNING: ptype info format error (end-quote): ' + ATypeText);
500
 
        Result.GdbDescription := ATypeText;
501
 
        CurPtr := @Result.GdbDescription[length(Result.GdbDescription)] + 1;
502
 
        break;
503
 
      end;
504
 
    end
505
 
    else begin
506
 
      // something wrong
507
 
      debugln('** WARNING: ptype info format error (start-quote): ' + ATypeText);
508
 
      Result.GdbDescription := ATypeText;
509
 
      CurPtr := @Result.GdbDescription[length(Result.GdbDescription)] + 1;
 
642
  Result.BaseDeclaration.Ptr := nil;
 
643
  Result.BaseDeclaration.Len := 0;
 
644
  Result.PointerCount := 0;
 
645
  Result.BoundLow.Ptr := nil;
 
646
  Result.BoundLow.Len := 0;
 
647
  Result.BoundHigh.Ptr := nil;
 
648
  Result.BoundHigh.Len := 0;
 
649
  Result.SubName.Ptr := nil;
 
650
  Result.SubName.Len := 0;
 
651
  Result.BaseSubName.Ptr := nil;
 
652
  Result.BaseSubName.Len := 0;
 
653
  Result.SubFlags := [];
 
654
  Result.SubKind := ptprkError;
 
655
  Result.NestArrayCount := 0;
 
656
  If (ATypeText = nil) or (ATypeTextLen = 0) then exit;
 
657
 
 
658
  (* type = [&^][name]
 
659
     type = [&^][name] = class|record : public
 
660
     type = [&^][name] = (a,b,c)
 
661
     type = [&^]array ...
 
662
     type = [&^]set of [name] = (a,b)
 
663
     type = [&^](.....)
 
664
  *)
 
665
 
 
666
 
 
667
 
 
668
  CurPtr := ATypeText;
 
669
  EndPtr := ATypeText + ATypeTextLen-1;
 
670
 
 
671
  while (EndPtr > CurPtr) and (EndPtr^ in [#10, #13, ' ']) do dec (EndPtr);
 
672
 
 
673
  LineEndPtr := EndPtr;
 
674
  //limit LineEndPtr to first \n
 
675
  HelpPtr := CurPtr;
 
676
  while (true) do begin
 
677
    if HelpPtr > LineEndPtr - 1 then break;
 
678
    if (HelpPtr[0] in [#10, #13])
 
679
    then begin
 
680
      LineEndPtr := HelpPtr-1;
 
681
      while (LineEndPtr > CurPtr) and (LineEndPtr^ in [#10, #13, ' ']) do dec (LineEndPtr);
510
682
      break;
511
683
    end;
512
 
    while (EndPtr^ in [#10, #13]) do inc(EndPtr);
 
684
    inc(HelpPtr);
513
685
  end;
514
 
  SetLength(Result.GdbDescription, CurPtr - @Result.GdbDescription[1]);
515
 
*)
516
 
 
517
 
  StartIdx := pos('type = ', Result.GdbDescription);
518
 
  if StartIdx <= 0 then exit;
519
 
  inc(StartIdx, 7);
520
 
  CurPtr := @Result.GdbDescription[StartIdx];
521
 
 
522
 
  EndIdx := pos(LineEnding, Result.GdbDescription); // the first \n, even if not on the first line
523
 
  if EndIdx <= 0 then EndIdx := length(Result.GdbDescription)+1;
524
 
  EndPtr := @Result.GdbDescription[EndIdx-1];
525
 
 
526
 
 
527
 
  // Pointer indicators
528
 
  DeclPtr := CurPtr;
 
686
 
 
687
 
 
688
  BaseDeclPtr := CurPtr;
 
689
  DeclPtr := BaseDeclPtr;
 
690
  DeclEndPtr := LineEndPtr;
 
691
 
 
692
  // Leading ^&
529
693
  while True do begin
530
694
    case CurPtr^ of
531
 
      '^': include(Result.Flags, ptprfPointer);
 
695
      '^': begin
 
696
          include(Result.Flags, ptprfPointer);
 
697
          inc(Result.PointerCount);
 
698
        end;
532
699
      '&': include(Result.Flags, ptprfParamByRef);
533
700
      else break;
534
701
    end;
535
702
    inc(CurPtr);
536
703
  end;
537
704
  SkipSpaces(CurPtr); // shouldn'tever happen
 
705
  BaseDeclPtr := CurPtr;
538
706
 
539
 
  if CurPtr > EndPtr then begin
 
707
  if CurPtr > LineEndPtr then begin
540
708
    include(Result.Flags, ptprfEmpty);
541
709
    exit;
542
710
  end;
543
711
 
 
712
  // entite type in brackest (), eg ^(array...)
 
713
  if CurPtr^ = '(' then begin
 
714
    Include(Result.Flags, ptprfDeclarationInBrackets);
 
715
    inc(CurPtr);
 
716
    SkipSpaces(CurPtr); // shouldn'tever happen
 
717
    BaseDeclPtr := CurPtr;
 
718
    DeclPtr := CurPtr; // not possible to capture with one line, as closing bracket may be on other line
 
719
    if DeclEndPtr^ = ')' then dec(DeclEndPtr);
 
720
    if LineEndPtr^ = ')' then dec(LineEndPtr);
 
721
    if EndPtr^ = ')' then dec(EndPtr);
 
722
  end;
 
723
 
 
724
  SetPCharLen(Result.BaseDeclaration, BaseDeclPtr, DeclEndPtr);
 
725
  SetPCharLen(Result.Declaration,     DeclPtr,     DeclEndPtr);
544
726
 
545
727
  if CurPtr^ = '=' then begin
546
 
    // un-nmaed type
 
728
    // skip ' = '
547
729
    inc(CurPtr);
548
730
    SkipSpaces(CurPtr);
549
 
 
550
 
    i := CheckIsEnum;
551
 
    if i > 0 then begin
552
 
      // un-named enum // type =  = (e1, e2, e3)
553
 
      Result.Kind := ptprkEnum;
554
 
      Result.Declaration.Ptr := CurPtr;
555
 
      Result.Declaration.Len := i;
556
 
      exit;
557
 
    end;
558
 
 
559
 
    // Unexpected, see if we have a keyword
560
 
    Result.Kind := CheckKeyword;
561
 
    if Result.Kind = ptprkSimple then begin
562
 
      Result.Kind := ptprkError;
563
 
      debugln('** WARNING: ptype info format error: ' + ATypeText);
564
 
      exit;
565
 
    end;
566
731
  end
567
 
 
568
 
  else
569
 
  begin
570
 
    if CurPtr^ = '(' then begin
571
 
      // type in brackets, eg ^(array...)
572
 
      inc(CurPtr);
573
 
    end;
574
 
    SkipSpaces(CurPtr); // shouldn'tever happen
575
 
 
 
732
  else begin
 
733
    // process part before ' = '
576
734
    Result.Kind := CheckKeyword;
577
 
    if Result.Kind = ptprkSimple then begin
 
735
    if Result.Kind = ptprkSimple
 
736
    then begin
578
737
      // we may have   type = NAME = ....
579
738
      HelpPtr := CurPtr;
580
 
      while not (HelpPtr^ in [#0..#31, ' ']) do inc(HelpPtr);
581
 
      HelpPtr2 := HelpPtr;
 
739
      while (HelpPtr <= LineEndPtr) and  not (HelpPtr^ in [#0..#31, ' ']) do inc(HelpPtr);
 
740
      HelpPtr2 := HelpPtr;  // HelpPtr2 = after [name]
582
741
      SkipSpaces(HelpPtr2);
583
 
      if ((HelpPtr^ = ' ') and ((HelpPtr2)^ = '='))
584
 
      or (HelpPtr^ in [#0, #10, #13])
 
742
 
 
743
      if (HelpPtr2^ = '=') or // TYPE WITH = (EQUAL)
 
744
         ((HelpPtr^ in [#0, #10, #13]) or (HelpPtr > LineEndPtr))
585
745
      then begin
586
746
        // Type without space, use as name
587
 
        Result.Name.Ptr := DeclPtr; //CurPtr;
588
 
        Result.Name.Len := HelpPtr - DeclPtr; // CurPtr;
589
 
        while DeclPtr^ in ['&', '^'] do inc(DeclPtr);
590
 
        Result.BaseName.Ptr := DeclPtr; //CurPtr;
591
 
        Result.BaseName.Len := HelpPtr - DeclPtr; // CurPtr;
592
 
        if (HelpPtr^ in [#0, #10, #13]) then exit;
593
 
 
594
 
        // now there must be a keyword or set
595
 
        CurPtr := HelpPtr2 + 1;
596
 
        // Todo: in this case the declaration doe not include the pointer, if any => maybe add flag?
 
747
        SetPCharLen(Result.Name,     DeclPtr, HelpPtr-1);
 
748
        SetPCharLen(Result.BaseName, BaseDeclPtr, HelpPtr-1);
 
749
 
 
750
        if (HelpPtr^ in [#0, #10, #13]) or (HelpPtr > LineEndPtr) then exit;
 
751
 
 
752
        CurPtr := HelpPtr2 + 1; // after ' = '
597
753
        SkipSpaces(CurPtr);
 
754
        BaseDeclPtr := CurPtr;  // Declaration after ' = '
598
755
        DeclPtr := CurPtr;
599
 
        i := CheckIsEnum;
600
 
        if i > 0 then begin
601
 
          Result.Kind := ptprkEnum;
602
 
          Result.Declaration.Ptr := CurPtr;
603
 
          Result.Declaration.Len := i;
604
 
          exit;
605
 
        end;
606
 
 
607
 
        Result.Kind := CheckKeyword;
608
 
        if Result.Kind = ptprkSimple then begin
609
 
          Result.Kind := ptprkError;
610
 
          debugln('** WARNING: ptype info format error: ' + ATypeText);
611
 
          exit;
612
 
        end;
613
756
      end
614
757
      else begin
615
758
        // Type is a declaration with spaces
616
 
        while EndPtr^ = ' ' do dec(EndPtr);
617
 
        Result.Declaration.Ptr := CurPtr;
618
 
        Result.Declaration.Len := EndPtr - CurPtr + 1;
 
759
        // (base)declaration is already set
619
760
        exit;
620
761
      end;
621
762
    end;
622
763
  end;
623
764
 
 
765
  // after ' = '
 
766
 
 
767
  i := CheckIsEnum;
 
768
  if i > 0 then begin
 
769
    Result.Kind := ptprkEnum;
 
770
    SetPCharLen(Result.BaseDeclaration, CurPtr, CurPtr+i-1);
 
771
    SetPCharLen(Result.Declaration,     CurPtr, CurPtr+i-1);
 
772
    exit;
 
773
  end;
 
774
 
 
775
  Result.Kind := CheckKeyword;
 
776
  if Result.Kind = ptprkSimple then begin
 
777
    Result.Kind := ptprkError;
 
778
    debugln('** WARNING: ptype info format error: ' + ATypeText);
 
779
    exit;
 
780
  end;
 
781
 
624
782
  // now we should be AT a keyword, we may have a name set already // Enum are handled already too
625
 
  while EndPtr^ = ' ' do dec(EndPtr);
 
783
  while LineEndPtr^ = ' ' do dec(LineEndPtr);
626
784
  case Result.Kind of
627
785
    ptprkClass: begin
628
786
        HelpPtr := CurPtr + 5;
629
787
        SkipSpaces(HelpPtr);
630
788
        if HelpPtr^ in [#10, #13] then include(Result.Flags, ptprfNoStructure);
631
 
        Result.Declaration.Ptr := DeclPtr;
632
 
        Result.Declaration.Len := EndPtr - DeclPtr + 1;
 
789
        SetPCharLen(Result.Declaration, DeclPtr, LineEndPtr);
633
790
      end;
634
791
    ptprkRecord: begin
635
792
        HelpPtr := CurPtr + 6;
636
793
        SkipSpaces(HelpPtr);
637
 
        Result.Declaration.Ptr := DeclPtr;
638
794
        if HelpPtr^ in ['{'] then begin
639
795
          include(Result.Flags, ptprfNoStructure);
640
 
          Result.Declaration.Len := CurPtr + 6 - DeclPtr;
 
796
          SetPCharLen(Result.Declaration, DeclPtr, CurPtr + 5);
641
797
        end
642
798
        else
643
 
          Result.Declaration.Len := EndPtr - DeclPtr + 1;
 
799
          SetPCharLen(Result.Declaration, DeclPtr, LineEndPtr);
644
800
      end;
645
801
    ptprkSet: begin
646
802
        if CurPtr^ <> '<' then begin;
647
 
          Result.Declaration.Ptr := DeclPtr;
648
 
          Result.Declaration.Len := EndPtr - DeclPtr + 1;
 
803
          SetPCharLen(Result.Declaration, DeclPtr, LineEndPtr);
 
804
          //CurPtr := Result.BaseDeclaration.Ptr + 3;
 
805
          CurPtr := CurPtr + 6;
 
806
          SkipSpaces(CurPtr);
 
807
          if (CurPtr^ = '=') then begin  // has enum, no name,
 
808
            CurPtr := CurPtr + 1;
 
809
            SkipSpaces(CurPtr);
 
810
          end;
 
811
          SetPCharLen(Result.SubName, CurPtr, LineEndPtr);
 
812
          while (CurPtr^ in ['^', '&']) and (CurPtr < LineEndPtr) do inc(CurPtr); // should not happen
 
813
          SetPCharLen(Result.BaseSubName, CurPtr, LineEndPtr);
 
814
          Result.SubKind := ptprkSimple;
 
815
        end
 
816
        else begin
 
817
          Result.Declaration.Ptr := nil;
 
818
          Result.Declaration.Len := 0;
 
819
          Result.BaseDeclaration.Ptr := nil;
 
820
          Result.BaseDeclaration.Len := 0;
649
821
        end;
650
822
      end;
651
823
    ptprkArray: begin
652
 
        Result.Declaration.Ptr := DeclPtr;
653
 
        Result.Declaration.Len := EndPtr - DeclPtr + 1;
 
824
        SetPCharLen(Result.Declaration, DeclPtr, LineEndPtr);
 
825
        SetPCharLen(Result.BaseDeclaration, BaseDeclPtr, LineEndPtr);
 
826
        CurPtr := CurPtr + 5;
 
827
        SkipSpaces(CurPtr);
 
828
        include(Result.Flags, ptprfNoBounds);
 
829
        include(Result.Flags, ptprfDynArray);
 
830
        if CurPtr^ = '[' then begin
 
831
          inc(CurPtr);
 
832
          HelpPtr := CurPtr;
 
833
          while (HelpPtr^ in ['-', '0'..'9']) and (HelpPtr < LineEndPtr - 3) do inc (HelpPtr);
 
834
          if (HelpPtr > CurPtr) and (HelpPtr^ = '.') and  ((HelpPtr+1)^ = '.') then begin
 
835
            HelpPtr2 := HelpPtr + 2;
 
836
            while (HelpPtr2^ in ['-', '0'..'9']) and (HelpPtr2 < LineEndPtr - 1) do inc (HelpPtr2);
 
837
            if (HelpPtr2 > HelpPtr) and (HelpPtr2^ = ']') then begin
 
838
              exclude(Result.Flags, ptprfNoBounds);
 
839
              Result.BoundLow.Ptr := CurPtr;
 
840
              Result.BoundLow.Len := HelpPtr - CurPtr;
 
841
              Result.BoundHigh.Ptr := HelpPtr + 2;
 
842
              Result.BoundHigh.Len := HelpPtr2 - (HelpPtr + 2);
 
843
              if (HelpPtr2 - CurPtr <> 5) or (strlcomp(Result.BoundLow.Ptr, PChar('0..-1'), 5) <> 0) then
 
844
                exclude(Result.Flags, ptprfDynArray);
 
845
              CurPtr := HelpPtr2 + 1;
 
846
            end;
 
847
          end;
 
848
        end;
 
849
 
 
850
        SkipSpaces(CurPtr);
 
851
        if (CurPtr^ in ['o', 'O']) and ((CurPtr+1)^ in ['f', 'F']) then begin
 
852
          CurPtr := CurPtr + 2;
 
853
          SkipSpaces(CurPtr);
 
854
 
 
855
          SubRes := ParseTypeFromGdb(CurPtr, EndPtr - CurPtr + 1);
 
856
          if SubRes.Kind = ptprkArray then begin
 
857
            Result.SubName        := SubRes.SubName;
 
858
            Result.BaseSubName    := SubRes.BaseSubName;
 
859
            Result.SubFlags       := SubRes.SubFlags;
 
860
            Result.SubKind        := SubRes.SubKind;
 
861
            Result.NestArrayCount := SubRes.NestArrayCount + 1;
 
862
            Result.NestArray      := SubRes.NestArray;
 
863
            if length(Result.NestArray) < Result.NestArrayCount
 
864
            then SetLength(Result.NestArray, Result.NestArrayCount + 3);
 
865
            Result.NestArray[SubRes.NestArrayCount].Flags        := SubRes.Flags;
 
866
            Result.NestArray[SubRes.NestArrayCount].PointerCount := SubRes.PointerCount;
 
867
            Result.NestArray[SubRes.NestArrayCount].BoundLow     := SubRes.BoundLow;
 
868
            Result.NestArray[SubRes.NestArrayCount].BoundHigh    := SubRes.BoundHigh;
 
869
          end else begin
 
870
            Result.SubName        := SubRes.Name;
 
871
            Result.BaseSubName    := SubRes.BaseName;
 
872
            Result.SubFlags       := SubRes.Flags;
 
873
            Result.SubKind        := SubRes.Kind;
 
874
          end;
 
875
 
 
876
 
 
877
          //SetPCharLen(Result.SubName, CurPtr, LineEndPtr);
 
878
          //while (CurPtr^ in ['^', '&']) and (CurPtr < LineEndPtr) do inc(CurPtr);
 
879
          //SetPCharLen(Result.BaseSubName, CurPtr, LineEndPtr);
 
880
        end;
654
881
      end;
655
882
    ptprkProcedure, ptprkFunction: begin
656
 
        Result.Declaration.Ptr := DeclPtr;
657
 
        Result.Declaration.Len := EndPtr - DeclPtr + 1;
658
 
      end;
659
 
  end;
 
883
        SetPCharLen(Result.Declaration, DeclPtr, LineEndPtr);
 
884
      end;
 
885
  end;
 
886
  finally
 
887
    DebugLn(DBGMI_TYPE_INFO, ['ParseTypeFromGdb: Flags=', dbgs(Result.Flags), ' Kind=', dbgs(Result.Kind), ' Name="', PCLenToString(Result.Name),'"' ]);
 
888
  end;
 
889
end;
 
890
 
 
891
function ParseTypeFromGdb(const ATypeText: string): TGDBPTypeResult;
 
892
var
 
893
  i: SizeInt;
 
894
begin
 
895
  i := pos('type = ', ATypeText);
 
896
  if i < 1
 
897
  then Result := ParseTypeFromGdb(PChar(ATypeText), length(ATypeText))
 
898
  else Result := ParseTypeFromGdb((@ATypeText[i])+7, length(ATypeText)-6-i);
 
899
  Result.GdbDescription := ATypeText;
 
900
end;
 
901
 
 
902
function dbgs(AFlag: TGDBPTypeResultFlag): string;
 
903
begin
 
904
  writestr(Result, AFlag);
 
905
end;
 
906
 
 
907
function dbgs(AFlags: TGDBPTypeResultFlags): string;
 
908
var
 
909
  i: TGDBPTypeResultFlag;
 
910
begin
 
911
  Result:='';
 
912
  for i := low(TGDBPTypeResultFlags) to high(TGDBPTypeResultFlags) do
 
913
    if i in AFlags then begin
 
914
      if Result <> '' then Result := Result + ', ';
 
915
      Result := Result + dbgs(i);
 
916
    end;
 
917
  if Result <> '' then Result := '[' + Result + ']';
 
918
end;
 
919
 
 
920
function dbgs(AKind: TGDBPTypeResultKind): string;
 
921
begin
 
922
  writestr(Result, AKind);
 
923
end;
 
924
 
 
925
function dbgs(AReqType: TGDBCommandRequestType): string;
 
926
begin
 
927
  WriteStr(Result, AReqType);
 
928
end;
 
929
 
 
930
function dbgs(AReq: TGDBPTypeRequest): string;
 
931
begin
 
932
  Result := 'Req="'+AReq.Request+'" type='+dbgs(AReq.ReqType)
 
933
    +' HasNext='+dbgs(AReq.Next <> nil)
 
934
    ;
 
935
end;
 
936
 
 
937
{ TGDBExpressionPartCommaList }
 
938
 
 
939
function TGDBExpressionPartCommaList.GetTextFixed(AStringFixed: Boolean): String;
 
940
var
 
941
  i: Integer;
 
942
begin
 
943
  Result := '';
 
944
  if PartCount = 0 then
 
945
    exit;
 
946
  Result := Parts[0].GetTextFixed(AStringFixed);
 
947
  for i := 1 to PartCount - 1 do
 
948
    Result := Result + ',' + Parts[i].GetTextFixed(AStringFixed);
 
949
end;
 
950
 
 
951
{ TGDBExpressionPartArrayIdx }
 
952
 
 
953
function TGDBExpressionPartArrayIdx.GetArrayPTypeIsDeRef: boolean;
 
954
begin
 
955
  Result := (FPTypeReq.Result.Kind <> ptprkArray);
 
956
end;
 
957
 
 
958
function TGDBExpressionPartArrayIdx.GetArrayPTypeIsPointer: boolean;
 
959
begin
 
960
  if FArrayPTypeNestIdx < 0 then begin
 
961
    if ArrayPTypeIsDeRef
 
962
    then Result := True
 
963
    else Result := ptprfPointer in FPTypeReq.Result.Flags;
 
964
  end
 
965
  else begin
 
966
    Result := ptprfPointer in ArrayPTypeResult.NestArray[FArrayPTypeNestIdx].Flags;
 
967
  end;
 
968
end;
 
969
 
 
970
function TGDBExpressionPartArrayIdx.GetArrayPTypeResult: TGDBPTypeResult;
 
971
begin
 
972
  Result := FPTypeReq.Result;
 
973
  if (Result.Kind <> ptprkArray) then
 
974
    Result := FPTypeDeRefReq.Result;
 
975
end;
 
976
 
 
977
procedure TGDBExpressionPartArrayIdx.Init;
 
978
begin
 
979
  inherited Init;
 
980
  FPTypeReq.Result.Kind := ptprkNotEvaluated;
 
981
  FPTypeDeRefReq.Result.Kind := ptprkNotEvaluated;
 
982
  FPTypeIndexReq.Result.Kind := ptprkNotEvaluated;
 
983
  FVarParam := False;
 
984
  FArrayPTypeNestidx := -1;
 
985
  FArrayPTypePointerIdx := 0;
 
986
end;
 
987
 
 
988
procedure TGDBExpressionPartArrayIdx.InitReq(var AReqPtr: PGDBPTypeRequest; AReqText: String);
 
989
begin
 
990
  InitReq(AReqPtr, FPTypeReq, AReqText, gcrtPType);
 
991
end;
 
992
 
 
993
procedure TGDBExpressionPartArrayIdx.InitDeRefReq(var AReqPtr: PGDBPTypeRequest;
 
994
  AReqText: String);
 
995
begin
 
996
  InitReq(AReqPtr, FPTypeDeRefReq, AReqText, gcrtPType);
 
997
end;
 
998
 
 
999
procedure TGDBExpressionPartArrayIdx.InitIndexReq(var AReqPtr: PGDBPTypeRequest);
 
1000
begin
 
1001
  InitReq(AReqPtr, FPTypeIndexReq,
 
1002
          GdbCmdEvaluate + Quote(GetPlainText), gcrtEvalExpr);
 
1003
end;
 
1004
 
 
1005
function TGDBExpressionPartArrayIdx.GetTextFixed(AStringFixed: Boolean): String;
 
1006
begin
 
1007
  if AStringFixed then begin
 
1008
    if FExpressionPart = nil
 
1009
    then Result := PCLenPartToString(FText, 1, FText.Len-2)
 
1010
    else Result := FExpressionPart.Text;
 
1011
    Result := FText.Ptr^ + Result + '-1' + (FText.Ptr + FText.Len-1)^;
 
1012
  end
 
1013
  else
 
1014
     Result := inherited GetTextFixed(AStringFixed);
 
1015
end;
 
1016
 
 
1017
function TGDBExpressionPartArrayIdx.CreateExpressionForSubIndex(AIndex: Integer): TGDBExpressionPartArrayIdx;
 
1018
begin
 
1019
  Result := TGDBExpressionPartArrayIdx.Create
 
1020
            (FText.Ptr^ + Parts[AIndex].GetText + (FText.Ptr + FText.Len-1)^);
 
1021
end;
 
1022
 
 
1023
{ TGDBExpressionPartList }
 
1024
 
 
1025
function TGDBExpressionPartList.AddList(APartList: TGDBExpressionPartList): Integer;
 
1026
var
 
1027
  i: Integer;
 
1028
begin
 
1029
  Result := -1;
 
1030
  if APartList.PartCount = 0 then exit;
 
1031
  Result := FList.add(APartList.Parts[0]);
 
1032
  for i := 1 to APartList.PartCount - 1 do
 
1033
    FList.add(APartList.Parts[i]);
 
1034
end;
 
1035
 
 
1036
{ TGDBExpressionPartArray }
 
1037
 
 
1038
function TGDBExpressionPartArray.GetIndexParts(Index: Integer): TGDBExpressionPartArrayIdx;
 
1039
var
 
1040
  j: Integer;
 
1041
begin
 
1042
  Result := TGDBExpressionPartArrayIdx(Parts[Index+1]);
 
1043
 
 
1044
  if Result.IsCommaSeparated then begin
 
1045
    Delete(Index+1);
 
1046
    For j := 0 to Result.PartCount-1 do
 
1047
      Insert(Index + 1 + j, Result.CreateExpressionForSubIndex(j));
 
1048
    Result.Free;
 
1049
    Result := TGDBExpressionPartArrayIdx(Parts[Index+1]);
 
1050
  end;
 
1051
end;
 
1052
 
 
1053
function TGDBExpressionPartArray.GetTextFixed(AStringFixed: Boolean): String;
 
1054
begin
 
1055
  Result := GetTextToIdx(IndexCount-1, AStringFixed);
 
1056
end;
 
1057
 
 
1058
function TGDBExpressionPartArray.GetTextToIdx(AIdx: Integer; AStrFixed: Boolean = False): String;
 
1059
 
 
1060
  function GetPointerCast(AnIdxPart: TGDBExpressionPartArrayIdx; out PointerCnt: Integer): String;
 
1061
  var
 
1062
    PTRes: TGDBPTypeResult;
 
1063
    i: Integer;
 
1064
  begin
 
1065
    Result := '';
 
1066
    PointerCnt := 0;
 
1067
    if not AnIdxPart.ArrayPTypeIsPointer then exit;
 
1068
    PTRes := AnIdxPart.ArrayPTypeResult;
 
1069
    if PTRes.SubName.Len = 0 then exit;
 
1070
 
 
1071
    i := PTRes.NestArrayCount - 1;
 
1072
    if i >= 0 then begin
 
1073
      while (i >= 0) and (ptprfPointer in PTRes.NestArray[i].Flags) do dec(i);
 
1074
      if i >= 0 then exit; // cant cast, if contains static array
 
1075
      PointerCnt := PTRes.NestArrayCount+1;
 
1076
      Result := StringOfChar('^', PointerCnt) + PCLenToString(PTRes.SubName);
 
1077
      exit;
 
1078
    end;
 
1079
 
 
1080
    PointerCnt := PTRes.PointerCount;
 
1081
    // If PTRes is the result of an extra de-ref in the ptype, then we need to add that pointer back
 
1082
    if AnIdxPart.ArrayPTypeIsDeRef then
 
1083
      inc(PointerCnt);
 
1084
    Result := StringOfChar('^', PointerCnt) + PCLenToString(PTRes.SubName);
 
1085
  end;
 
1086
 
 
1087
var
 
1088
  i, j, PCastCnt: Integer;
 
1089
  IdxPart: TGDBExpressionPartArrayIdx;
 
1090
  PTResult: TGDBPTypeResult;
 
1091
  NeedTCast: Boolean;
 
1092
  s: String;
 
1093
begin
 
1094
  Result := Parts[0].Text;
 
1095
  PCastCnt := 0;
 
1096
 
 
1097
  if AIdx < 0 then exit;
 
1098
 
 
1099
  for i := 0 to AIdx do begin
 
1100
    IdxPart := TGDBExpressionPartArrayIdx(Parts[i + 1]);
 
1101
    PTResult := IdxPart.ArrayPTypeResult;
 
1102
    if PCastCnt > 0 then dec(PCastCnt);
 
1103
 
 
1104
    if not (PTResult.Kind = ptprkArray)
 
1105
    then begin
 
1106
      // maybe pointer with index access
 
1107
      if AStrFixed and (i = IndexCount - 1)
 
1108
      then Result := Result + IdxPart.TextStrFixed
 
1109
      else Result := Result + IdxPart.Text;
 
1110
      continue;
 
1111
    end;
 
1112
 
 
1113
    if ((PTResult.NestArrayCount > 0) and (IdxPart.ArrayPTypeNestIdx <> PTResult.NestArrayCount-1)) or
 
1114
       (IdxPart.ArrayPTypePointerIdx > 0)
 
1115
    then begin
 
1116
      // nested array / no named type known
 
1117
      if (PCastCnt = 0) and IdxPart.ArrayPTypeIsPointer
 
1118
      then Result := Result + '^';
 
1119
      Result := Result + IdxPart.Text;
 
1120
      continue;
 
1121
    end;
 
1122
 
 
1123
 
 
1124
    NeedTCast := FNeedTypeCast and (i = IndexCount-1);
 
1125
 
 
1126
    if IdxPart.ArrayPTypeIsPointer
 
1127
    then begin
 
1128
      //dyn array
 
1129
      s := '';
 
1130
      if IdxPart.VarParam then
 
1131
        s := GetPointerCast(IdxPart, j);
 
1132
      if s <> '' // IdxPart.VarParam and (PTResult.SubName.Len > 0)                        // var param can only be set for the un-inxed variable
 
1133
      then begin
 
1134
        // fpc 2.4.4 Var-param dynarray
 
1135
        // var param are marked with a "&" in fpc 2.4. They are a semi automatic pointer.
 
1136
        // Any such var param, that points to an internal pointer type (e.g dyn array) must be typecasted, to trigger the semi automatic pointer of the var-param
 
1137
        // For single dyn array: ^Foo(var)[1]
 
1138
        // For nested dyn array: ^^Foo(var)[1][2]  // the ^ in front of the index must be skipped, as the dyn array was casted into a pointer
 
1139
        Result := s + '(' + Result + ')';
 
1140
        NeedTCast := False;
 
1141
        PCastCnt := j;
 
1142
      end
 
1143
      else
 
1144
      if (PCastCnt = 0) then
 
1145
        Result := Result + '^';
 
1146
    end;
 
1147
 
 
1148
    Result := Result + IdxPart.Text;
 
1149
 
 
1150
    if NeedTCast and (PTResult.SubName.Len > 0)
 
1151
    then
 
1152
      Result := PCLenToString(PTResult.SubName) + '(' + Result + ')';
 
1153
 
 
1154
  end;
 
1155
 
 
1156
end;
 
1157
 
 
1158
function TGDBExpressionPartArray.IndexCount: Integer;
 
1159
begin
 
1160
  Result := PartCount - 1;
 
1161
end;
 
1162
 
 
1163
constructor TGDBExpressionPartArray.Create(ALeadExpresion: TGDBExpressionPart);
 
1164
begin
 
1165
  inherited Create;
 
1166
  FNeedTypeCast := False;
 
1167
  Add(ALeadExpresion);
 
1168
end;
 
1169
 
 
1170
function TGDBExpressionPartArray.AddIndex(APart: TGDBExpressionPartArrayIdx): Integer;
 
1171
begin
 
1172
  Result := Add(APart);
 
1173
end;
 
1174
 
 
1175
function TGDBExpressionPartArray.NeedValidation(var AReqPtr: PGDBPTypeRequest): Boolean;
 
1176
  function IsNumber(s: String): Boolean;
 
1177
  var i: Integer;
 
1178
  begin
 
1179
    i := Length(s);
 
1180
    while (i >= 1) and (s[i] in ['0'..'9']) do dec(i);
 
1181
    Result := i = 0;
 
1182
  end;
 
1183
var
 
1184
  i, j: Integer;
 
1185
  IdxPart, IdxPart2: TGDBExpressionPartArrayIdx;
 
1186
  PTReq, PTDeRefReq: TGDBPTypeRequest;
 
1187
  ArrRes: TGDBPTypeResult;
 
1188
  ResultList: TGDBMINameValueList;
 
1189
  s: String;
 
1190
begin
 
1191
  Result := False;
 
1192
  // Index
 
1193
  for i := 1 to PartCount - 1 do
 
1194
    if Parts[i].NeedValidation(AReqPtr) then
 
1195
      Result := True;
 
1196
 
 
1197
  if Parts[0].NeedValidation(AReqPtr) // Array-Variable
 
1198
  then begin
 
1199
    Result := True;
 
1200
    exit;
 
1201
  end;
 
1202
  if Result then exit;
 
1203
 
 
1204
  i := 0;
 
1205
  while i < IndexCount do begin
 
1206
    // IdxPart is the NEXT index. We evaluate the expression BEFORE IdxPart
 
1207
    IdxPart := IndexPart[i];
 
1208
    PTReq := IdxPart.PTypeReq;
 
1209
 
 
1210
    if PTReq.Result.Kind = ptprkError
 
1211
    then begin
 
1212
      // "Parts[i]" Check if the part before IndexParts[i] needs typecastfixing
 
1213
      if (pos('address 0x0', PTReq.Error) > 0) and Parts[i].MayNeedTypeCastFix
 
1214
      then begin
 
1215
        Result := Parts[i].NeedValidation(AReqPtr);
 
1216
        PTReq.Result.Kind := ptprkNotEvaluated; // Reset the request
 
1217
        IdxPart.PTypeReq := PTReq;
 
1218
      end;
 
1219
 
 
1220
      exit; // If Result = False; // no way to find more info
 
1221
            // Todo, simply to next entry, and check for "pointer math on incomplete type"
 
1222
    end;
 
1223
 
 
1224
    if PTReq.Result.Kind = ptprkNotEvaluated
 
1225
    then begin
 
1226
      IdxPart.VarParam := False;
 
1227
      // InitReq sets: PTReq.Result.Kind = ptprkError;
 
1228
      IdxPart.InitReq(AReqPtr, GdbCmdPType + GetTextToIdx(i-1));
 
1229
      Result := True;
 
1230
      exit;
 
1231
    end
 
1232
    else
 
1233
    if (not IdxPart.VarParam) and (ptprfParamByRef in PTReq.Result.Flags)
 
1234
    then begin
 
1235
      // FPC 2.2.4 encoded "var param" in a special way, and we need an extra deref)
 
1236
      IdxPart.VarParam := True;
 
1237
      IdxPart.InitReq(AReqPtr, GdbCmdPType + GetTextToIdx(i-1) + '^');
 
1238
      Result := True;
 
1239
      exit;
 
1240
    end;
 
1241
 
 
1242
    (* With Dwarf gdb may return "type = ^TFoo" for an array
 
1243
       And the for the derefferenced expr "type = array of TFoo"
 
1244
    *)
 
1245
    PTDeRefReq := IdxPart.PTypeDeRefReq;
 
1246
    if (PTReq.Result.Kind <> ptprkArray) and
 
1247
       (ptprfPointer in PTReq.Result.Flags) and
 
1248
       (PTDeRefReq.Result.Kind = ptprkNotEvaluated)
 
1249
    then begin
 
1250
      if IdxPart.VarParam
 
1251
      then IdxPart.InitDeRefReq(AReqPtr, GdbCmdPType + GetTextToIdx(i-1) + '^^')
 
1252
      else IdxPart.InitDeRefReq(AReqPtr, GdbCmdPType + GetTextToIdx(i-1) + '^');
 
1253
      Result := True;
 
1254
      exit;
 
1255
    end;
 
1256
 
 
1257
    // we may have nested array (dyn array only):
 
1258
    // - ^^(array ...)
 
1259
    // - array ... oaf array
 
1260
    // A combination of both is not expected
 
1261
 
 
1262
    ArrRes := IdxPart.ArrayPTypeResult;
 
1263
    if (ArrRes.Kind = ptprkArray) and (ArrRes.NestArrayCount > 0) then begin
 
1264
      j := ArrRes.NestArrayCount;
 
1265
      while j > 0 do begin
 
1266
        inc(i);
 
1267
        dec(j);
 
1268
        if i >= IndexCount then break;
 
1269
        IdxPart2 := IndexPart[i];
 
1270
        IdxPart2.PTypeReq      := IdxPart.PTypeReq;
 
1271
        IdxPart2.PTypeDeRefReq := IdxPart.PTypeDeRefReq;
 
1272
        IdxPart2.ArrayPTypeNestIdx := j;
 
1273
      end;
 
1274
    end
 
1275
 
 
1276
    else
 
1277
    if (ArrRes.Kind = ptprkArray) and (ArrRes.PointerCount > 1) then begin
 
1278
      j := ArrRes.PointerCount - 1;
 
1279
      while j > 0 do begin
 
1280
        inc(i);
 
1281
        dec(j);
 
1282
        if i >= IndexCount then break;
 
1283
        IdxPart2 := IndexPart[i];
 
1284
        IdxPart2.PTypeReq      := IdxPart.PTypeReq;
 
1285
        IdxPart2.PTypeDeRefReq := IdxPart.PTypeDeRefReq;
 
1286
        IdxPart2.ArrayPTypePointerIdx := j;
 
1287
      end;
 
1288
    end;
 
1289
 
 
1290
    inc(i);
 
1291
  end;
 
1292
 
 
1293
  if IndexCount=0 then exit;
 
1294
 
 
1295
  // check if we may access a char in a string
 
1296
  IdxPart := IndexPart[IndexCount-1];
 
1297
  PTReq := IdxPart.PTypeReq;
 
1298
  if (PTReq.Result.Kind = ptprkSimple) and
 
1299
     not(IdxPart.PTypeDeRefReq.Result.Kind = ptprkArray)
 
1300
  then begin
 
1301
    s := LowerCase(PCLenToString(PTReq.Result.BaseName));
 
1302
    if (ptprfPointer in PTReq.Result.Flags) and
 
1303
       ( ( s = 'char') or (s = 'character') or (s = 'wchar') or (s = 'widechar') )
 
1304
    then begin
 
1305
      if IsNumber(IdxPart.GetPlainText)
 
1306
      then begin
 
1307
        FMaybeString := True;
 
1308
      end
 
1309
      else begin
 
1310
        PTReq := IdxPart.PTypeIndexReq;
 
1311
        if PTReq.Result.Kind = ptprkNotEvaluated
 
1312
        then begin
 
1313
          IdxPart.InitIndexReq(AReqPtr);
 
1314
          Result := True;
 
1315
          exit;
 
1316
        end;
 
1317
 
 
1318
        if (PTReq.Result.Kind = ptprkSimple)
 
1319
        then begin
 
1320
          ResultList := TGDBMINameValueList.Create(PTReq.Result.GdbDescription);
 
1321
          FMaybeString := IsNumber(ResultList.Values['value']);
 
1322
          ResultList.Free;
 
1323
        end;
 
1324
      end;
 
1325
    end;
 
1326
  end;
 
1327
 
 
1328
end;
 
1329
 
 
1330
function TGDBExpressionPartArray.MayNeedStringFix: Boolean;
 
1331
begin
 
1332
  Result := FMaybeString;
 
1333
  if not Result then
 
1334
    Result := inherited MayNeedStringFix;
 
1335
end;
 
1336
 
 
1337
{ TGDBExpressionPartCastCall }
 
1338
 
 
1339
procedure TGDBExpressionPartCastCall.Init;
 
1340
begin
 
1341
  inherited Init;
 
1342
  FPTypeReq.Result.Kind := ptprkNotEvaluated;
 
1343
end;
 
1344
 
 
1345
function TGDBExpressionPartCastCall.GetTextFixed(AStringFixed: Boolean): String;
 
1346
begin
 
1347
  Result := inherited GetTextFixed(AStringFixed);
 
1348
  if FTypeCastFixFlag = tcfFixNeeded then
 
1349
    Result := '^'+Result;
 
1350
end;
 
1351
 
 
1352
function TGDBExpressionPartCastCall.NeedValidation(var AReqPtr: PGDBPTypeRequest): Boolean;
 
1353
begin
 
1354
  Result := inherited NeedValidation(AReqPtr);
 
1355
 
 
1356
  if IsFunction or (FTypeCastFixFlag <> tcfEvalNeeded) then
 
1357
    exit;
 
1358
 
 
1359
  if FPTypeReq.Result.Kind = ptprkNotEvaluated then begin
 
1360
    InitReq(AReqPtr, FPTypeReq, GdbCmdPType + Parts[0].GetText , gcrtPType);
 
1361
    Result := True;
 
1362
    exit;
 
1363
  end;
 
1364
 
 
1365
  if (FPTypeReq.Result.Kind = ptprkError) or (FPTypeReq.Error <> '') then begin
 
1366
    FTypeCastFixFlag := tcfNoFixNeeded;
 
1367
    exit;
 
1368
  end;
 
1369
 
 
1370
  if FPTypeReq.Result.Kind = ptprkClass then begin
 
1371
    FTypeCastFixFlag := tcfFixNeeded;
 
1372
    FIsTypeCast := True;
 
1373
    exit;
 
1374
  end;
 
1375
 
 
1376
  if FPTypeReq.Result.Kind = ptprkRecord then begin // Includes pointer to array
 
1377
    FTypeCastFixFlag := tcfNoFixNeeded; // TODO: Maybe it is needed?
 
1378
    FIsTypeCast := True;
 
1379
    exit;
 
1380
  end;
 
1381
 
 
1382
  if FPTypeReq.Result.Kind in [ptprkProcedure, ptprkFunction] then begin
 
1383
    FTypeCastFixFlag := tcfNoFixNeeded;
 
1384
    FIsFunction := True;
 
1385
    exit;
 
1386
  end;
 
1387
 
 
1388
  FTypeCastFixFlag := tcfNoFixNeeded;
 
1389
end;
 
1390
 
 
1391
constructor TGDBExpressionPartCastCall.Create(ALeadExpresion: TGDBExpressionPart);
 
1392
var
 
1393
  i, l: Integer;
 
1394
  s: String;
 
1395
begin
 
1396
  inherited Create;
 
1397
  Add(ALeadExpresion);
 
1398
  FIsFunction := False;
 
1399
  FIsTypeCast := False;
 
1400
  FTypeCastFixFlag := tcfUnknown;
 
1401
  s := ALeadExpresion.GetText;
 
1402
  i := 1;
 
1403
  l := Length(s);
 
1404
  while (i <= l) and (s[i] in [' ', #9]) do inc(i);
 
1405
  if i < l then begin
 
1406
    while (i <= l) and (s[i] in ['a'..'z', 'A'..'Z', '0'..'9', '_']) do inc(i);
 
1407
    while (i <= l) and (s[i] in [' ', #9]) do inc(i);
 
1408
    FIsFunction := i < l;  // Contains chars that are not allowed in type identifiers (like foo.bar())
 
1409
  end;
 
1410
 
 
1411
end;
 
1412
 
 
1413
function TGDBExpressionPartCastCall.AddBrackets(APart: TGDBExpressionPart): Integer;
 
1414
begin
 
1415
  Result := Add(APart);
 
1416
end;
 
1417
 
 
1418
function TGDBExpressionPartCastCall.MayNeedTypeCastFix: Boolean;
 
1419
begin
 
1420
  Result := inherited MayNeedTypeCastFix;
 
1421
  if IsFunction then
 
1422
    exit;
 
1423
 
 
1424
  if not(FTypeCastFixFlag in [tcfUnknown, tcfEvalNeeded]) then
 
1425
    exit;
 
1426
 
 
1427
  Result := True;
 
1428
  FTypeCastFixFlag := tcfEvalNeeded;
 
1429
end;
 
1430
 
 
1431
{ TGDBExpressionPartBracketed }
 
1432
 
 
1433
function TGDBExpressionPartBracketed.GetTextFixed(AStringFixed: Boolean): String;
 
1434
begin
 
1435
  if FExpressionPart = nil
 
1436
  then Result := inherited GetTextFixed(AStringFixed)
 
1437
  else Result := FText.Ptr^ + FExpressionPart.GetTextFixed(AStringFixed) + (FText.Ptr + FText.Len-1)^;
 
1438
end;
 
1439
 
 
1440
function TGDBExpressionPartBracketed.GetPlainText: String;
 
1441
begin
 
1442
  if FExpressionPart = nil
 
1443
  then Result := PCLenPartToString(FText, 1, FText.Len-2)
 
1444
  else Result := FExpressionPart.Text;
 
1445
end;
 
1446
 
 
1447
constructor TGDBExpressionPartBracketed.Create(AText: PChar; ATextLen: Integer);
 
1448
begin
 
1449
  CreateSimple(AText, ATextLen);
 
1450
  FExpressionPart := ParseExpression(FText.Ptr+1, FText.Len-2);
 
1451
end;
 
1452
 
 
1453
{ TGDBExpressionPart }
 
1454
 
 
1455
function TGDBExpressionPart.GetTextFixed(AStringFixed: Boolean): String;
 
1456
begin
 
1457
  Result := PCLenToString(FText);
 
1458
end;
 
1459
 
 
1460
function TGDBExpressionPart.GetText: String;
 
1461
begin
 
1462
  Result := GetTextFixed(False);
 
1463
end;
 
1464
 
 
1465
function TGDBExpressionPart.ParseExpression(AText: PChar; ATextLen: Integer): TGDBExpressionPart;
 
1466
const
 
1467
  // include "." (dots). currently there is no need to break expressions like "foo.bar"
 
1468
  // Include "^" (deref)
 
1469
  // do NOT include "@", it is applied after []() resolution
 
1470
  WordChar = ['a'..'z', 'A'..'Z', '0'..'9', '_', '#', '$', '%', '&', '^', '.'];
 
1471
var
 
1472
  CurPtr, EndPtr: PChar;
 
1473
  CurPartPtr: PChar;
 
1474
 
 
1475
  procedure SkipSpaces;
 
1476
  begin
 
1477
    while (CurPtr < EndPtr) and (CurPtr^ in [#9, ' ']) do inc(CurPtr);
 
1478
  end;
 
1479
 
 
1480
  procedure ScanToWordEnd;
 
1481
  var
 
1482
    c: Char;
 
1483
    f: Boolean;
 
1484
  begin
 
1485
    // include "." (dots). currently there is no need to break expressions like "foo.bar"
 
1486
    // Include "^" (deref)
 
1487
    while (CurPtr < EndPtr) do begin
 
1488
      c := CurPtr^;
 
1489
      if (c in WordChar) then begin
 
1490
        inc(CurPtr);
 
1491
      end
 
1492
      else if (c in [' ', #9]) then begin
 
1493
        f := ((CurPtr-1)^ in ['.', '^']);
 
1494
        SkipSpaces;
 
1495
        if not(f  or  ((CurPtr < EndPtr) and (CurPtr^ in ['.', '^'])) ) then
 
1496
          break;
 
1497
      end
 
1498
      else
 
1499
        break;
 
1500
    end;
 
1501
  end;
 
1502
 
 
1503
  procedure ScanToWordStart;
 
1504
  begin
 
1505
    while (CurPtr < EndPtr) and not( (CurPtr^ in WordChar) or (CurPtr^  = ',') )
 
1506
    do inc(CurPtr);
 
1507
  end;
 
1508
 
 
1509
  function ScanToCallCastEnd: Boolean;
 
1510
  var
 
1511
    i: Integer;
 
1512
  begin
 
1513
    i := 0;
 
1514
    while (CurPtr < EndPtr) do begin
 
1515
      case CurPtr^ of
 
1516
        '(': inc(i);
 
1517
        ')': begin
 
1518
            dec(i);
 
1519
            inc(CurPtr);
 
1520
            if i = 0
 
1521
            then break
 
1522
            else continue;
 
1523
          end;
 
1524
      end;
 
1525
      inc(CurPtr);
 
1526
    end;
 
1527
    Result := i = 0;
 
1528
  end;
 
1529
 
 
1530
  function ScanToIndexEnd: Boolean;
 
1531
  var
 
1532
    i: Integer;
 
1533
  begin
 
1534
    i := 0;
 
1535
    while (CurPtr < EndPtr) do begin
 
1536
      case CurPtr^ of
 
1537
        '[': inc(i);
 
1538
        ']': begin
 
1539
            dec(i);
 
1540
            inc(CurPtr);
 
1541
            if i = 0
 
1542
            then break
 
1543
            else continue;
 
1544
          end;
 
1545
      end;
 
1546
      inc(CurPtr);
 
1547
    end;
 
1548
    Result := i = 0;
 
1549
  end;
 
1550
 
 
1551
  procedure AddExpPart(aList: TGDBExpressionPartList);
 
1552
  var
 
1553
    NewList: TGDBExpressionPartList;
 
1554
  begin
 
1555
    if aList.PartCount = 0 then exit;
 
1556
    if (aList.PartCount = 1) and (Result = nil) then begin
 
1557
      Result := aList.Parts[0];
 
1558
      aList.ClearShared;
 
1559
      exit;
 
1560
    end;
 
1561
 
 
1562
    If Result = nil
 
1563
    then Result := TGDBExpressionPartList.Create
 
1564
    else
 
1565
    if not (Result is TGDBExpressionPartList)
 
1566
    then begin
 
1567
      NewList := TGDBExpressionPartList.Create;
 
1568
      NewList.Add(Result);
 
1569
      Result := NewList;
 
1570
    end;
 
1571
 
 
1572
    TGDBExpressionPartList(Result).AddList(aList);
 
1573
    aList.ClearShared;
 
1574
  end;
 
1575
 
 
1576
  function MoveListToCopy(aList: TGDBExpressionPartList): TGDBExpressionPart;
 
1577
  begin
 
1578
    if aList.PartCount = 1
 
1579
    then begin
 
1580
      Result := aList.Parts[0];
 
1581
    end
 
1582
    else begin
 
1583
      Result := TGDBExpressionPartList.Create;
 
1584
      TGDBExpressionPartList(Result).AddList(aList);
 
1585
    end;
 
1586
    aList.ClearShared;
 
1587
  end;
 
1588
 
 
1589
var
 
1590
  CurList: TGDBExpressionPartList;
 
1591
  CurArray: TGDBExpressionPartArray;
 
1592
  CurCast: TGDBExpressionPartCastCall;
 
1593
  FCommaList: TGDBExpressionPartCommaList;
 
1594
  CurWord: TGDBExpression;
 
1595
begin
 
1596
  Result := nil;
 
1597
  FCommaList := nil;
 
1598
  CurPtr := AText;
 
1599
  EndPtr := AText + ATextLen;
 
1600
 
 
1601
  while (CurPtr < EndPtr) and not(CurPtr^ in ['[', '(', ',']) do inc(CurPtr);
 
1602
  if CurPtr = EndPtr then exit; // no fixup needed
 
1603
 
 
1604
  CurPtr := AText;
 
1605
  CurList:= TGDBExpressionPartList.Create;
 
1606
 
 
1607
  while CurPtr < EndPtr do begin
 
1608
 
 
1609
    if (CurPtr^ = ',')
 
1610
    then begin
 
1611
      if FCommaList = nil then
 
1612
        FCommaList := TGDBExpressionPartCommaList.Create;
 
1613
      AddExpPart(CurList);
 
1614
      FCommaList.Add(Result);
 
1615
      Result := nil;
 
1616
      inc(CurPtr);
 
1617
    end
 
1618
    else
 
1619
    if CurPtr^ in WordChar
 
1620
    then begin
 
1621
      CurPartPtr := CurPtr;
 
1622
      ScanToWordEnd;
 
1623
      CurWord := TGDBExpression.CreateSimple(CurPartPtr, CurPtr - CurPartPtr);
 
1624
      CurList.Add(CurWord);
 
1625
      if (CurPtr^ in WordChar) or CurWord.IsNamedOperator then // 2 words => named operator (and/or)
 
1626
        AddExpPart(CurList);
 
1627
    end
 
1628
    else
 
1629
    if (CurList.PartCount > 0) and (CurPtr^ = '[')
 
1630
    then begin
 
1631
      CurArray := TGDBExpressionPartArray.Create(MoveListToCopy(CurList));
 
1632
      CurList.Add(CurArray);
 
1633
      while (CurPtr^ = '[') do begin
 
1634
        CurPartPtr := CurPtr;
 
1635
        if not ScanToIndexEnd then break; // broken expression, do not attempt to do anything
 
1636
        CurArray.AddIndex(TGDBExpressionPartArrayIdx.Create(CurPartPtr, CurPtr - CurPartPtr));
 
1637
        SkipSpaces;
 
1638
      end;
 
1639
      if (CurPtr < EndPtr ) and (CurPtr^ in ['.', '^', '(']) then
 
1640
        CurArray.NeedTypeCast := True;
 
1641
    end
 
1642
    else
 
1643
    if (CurList.PartCount > 0) and (CurPtr^ = '(')
 
1644
    then begin
 
1645
      CurCast := TGDBExpressionPartCastCall.Create(MoveListToCopy(CurList));
 
1646
      CurList.Add(CurCast);
 
1647
      CurPartPtr := CurPtr;
 
1648
      if not ScanToCallCastEnd then break; // broken expression, do not attempt to do anything
 
1649
      CurCast.AddBrackets(TGDBExpressionPartBracketed.Create(CurPartPtr, CurPtr - CurPartPtr));
 
1650
    end
 
1651
    else begin
 
1652
      CurPartPtr := CurPtr;
 
1653
      ScanToWordStart;
 
1654
      CurList.Add(TGDBExpression.CreateSimple(CurPartPtr, CurPtr - CurPartPtr));
 
1655
      AddExpPart(CurList);
 
1656
    end;
 
1657
 
 
1658
  end;
 
1659
 
 
1660
  AddExpPart(CurList);
 
1661
  CurList.Free;
 
1662
 
 
1663
  if FCommaList <> nil then begin
 
1664
    if Result <> nil then
 
1665
      FCommaList.Add(Result);
 
1666
    Result := FCommaList;
 
1667
  end;
 
1668
 
 
1669
 
 
1670
  if CurPtr < EndPtr then debugln(['Scan aborted: ', PCLenToString(FText)]);
 
1671
  if CurPtr < EndPtr then FreeAndNil(Result);
 
1672
end;
 
1673
 
 
1674
procedure TGDBExpressionPart.Init;
 
1675
begin
 
1676
  //
 
1677
end;
 
1678
 
 
1679
procedure TGDBExpressionPart.InitReq(var AReqPtr: PGDBPTypeRequest;
 
1680
  var AReqVar: TGDBPTypeRequest; AReqText: String; AType: TGDBCommandRequestType);
 
1681
begin
 
1682
  AReqVar.Request := AReqText;
 
1683
  AReqVar.Error := '';
 
1684
  AReqVar.ReqType := AType;
 
1685
  AReqVar.Next := AReqPtr;
 
1686
  AReqVar.Result.Kind := ptprkError;
 
1687
  AReqPtr := @AReqVar;
 
1688
end;
 
1689
 
 
1690
function TGDBExpressionPart.NeedValidation(var AReqPtr: PGDBPTypeRequest): Boolean;
 
1691
var
 
1692
  i: Integer;
 
1693
begin
 
1694
  Result := False;
 
1695
  for i := 0 to PartCount - 1 do
 
1696
    if Parts[i].NeedValidation(AReqPtr) then
 
1697
      Result := True;
 
1698
end;
 
1699
 
 
1700
function TGDBExpressionPart.MayNeedStringFix: Boolean;
 
1701
var
 
1702
  i: Integer;
 
1703
begin
 
1704
  Result := False;
 
1705
  for i := 0 to PartCount - 1 do
 
1706
    if Parts[i].MayNeedStringFix then
 
1707
      Result := True;
 
1708
end;
 
1709
 
 
1710
function TGDBExpressionPart.MayNeedTypeCastFix: Boolean;
 
1711
var
 
1712
  i: Integer;
 
1713
begin
 
1714
  Result := False;
 
1715
  for i := 0 to PartCount - 1 do
 
1716
    if Parts[i].MayNeedTypeCastFix then
 
1717
      Result := True;
 
1718
end;
 
1719
 
 
1720
constructor TGDBExpressionPart.Create;
 
1721
begin
 
1722
  Init;
 
1723
end;
 
1724
 
 
1725
function TGDBExpressionPart.IsNamedOperator: Boolean;
 
1726
var
 
1727
  s: String;
 
1728
begin
 
1729
  s := LowerCase(Trim(GetText));
 
1730
  Result := (s = 'not') or (s = 'or') or (s = 'xor') or (s = 'and');
 
1731
end;
 
1732
 
 
1733
function TGDBExpressionPart.GetTextStrFixed: String;
 
1734
begin
 
1735
  Result := GetTextFixed(True);
 
1736
end;
 
1737
 
 
1738
function TGDBExpressionPart.GetParts(Index: Integer): TGDBExpressionPart;
 
1739
begin
 
1740
  Result := nil;
 
1741
end;
 
1742
 
 
1743
function TGDBExpressionPart.PartCount: Integer;
 
1744
begin
 
1745
  Result := 0;
 
1746
end;
 
1747
 
 
1748
{ TGDBExpressionPartListBase }
 
1749
 
 
1750
function TGDBExpressionPartListBase.GetParts(Index: Integer): TGDBExpressionPart;
 
1751
begin
 
1752
  Result := TGDBExpressionPart(FList[Index]);
 
1753
end;
 
1754
 
 
1755
function TGDBExpressionPartListBase.GetTextFixed(AStringFixed: Boolean): String;
 
1756
var
 
1757
  i: Integer;
 
1758
begin
 
1759
  Result := '';
 
1760
  for i := 0 to PartCount - 1 do
 
1761
    Result := Result + Parts[i].GetTextFixed(AStringFixed);
 
1762
end;
 
1763
 
 
1764
constructor TGDBExpressionPartListBase.Create;
 
1765
begin
 
1766
  inherited Create;
 
1767
  FList := TFPList.Create;
 
1768
end;
 
1769
 
 
1770
destructor TGDBExpressionPartListBase.Destroy;
 
1771
begin
 
1772
  Clear;
 
1773
  FreeAndNil(FList);
 
1774
  inherited Destroy;
 
1775
end;
 
1776
 
 
1777
procedure TGDBExpressionPartListBase.Clear;
 
1778
begin
 
1779
  while FList.Count > 0 do begin
 
1780
    TGDBExpressionPart(Flist[0]).Free;
 
1781
    FList.Delete(0);
 
1782
  end;
 
1783
end;
 
1784
 
 
1785
procedure TGDBExpressionPartListBase.ClearShared;
 
1786
begin
 
1787
  FList.Clear;
 
1788
end;
 
1789
 
 
1790
function TGDBExpressionPartListBase.Add(APart: TGDBExpressionPart): Integer;
 
1791
begin
 
1792
  Result := FList.Add(APart);
 
1793
end;
 
1794
 
 
1795
procedure TGDBExpressionPartListBase.Insert(AIndex: Integer; APart: TGDBExpressionPart);
 
1796
begin
 
1797
  FList.Insert(AIndex, APart);
 
1798
end;
 
1799
 
 
1800
procedure TGDBExpressionPartListBase.Delete(AIndex: Integer);
 
1801
begin
 
1802
  FList.Delete(AIndex);
 
1803
end;
 
1804
 
 
1805
function TGDBExpressionPartListBase.PartCount: Integer;
 
1806
begin
 
1807
  Result := FList.Count;
 
1808
end;
 
1809
 
 
1810
{ TGDBExpression }
 
1811
 
 
1812
function TGDBExpression.GetTextFixed(AStringFixed: Boolean): String;
 
1813
begin
 
1814
  if FExpressionPart = nil
 
1815
  then Result := inherited GetTextFixed(AStringFixed)
 
1816
  else Result := FExpressionPart.GetTextFixed(AStringFixed);
 
1817
end;
 
1818
 
 
1819
function TGDBExpression.GetParts(Index: Integer): TGDBExpressionPart;
 
1820
begin
 
1821
  Result := nil;
 
1822
  if FExpressionPart = nil then exit;
 
1823
  if FExpressionPart is TGDBExpressionPartList
 
1824
  then Result := FExpressionPart.Parts[Index]
 
1825
  else Result := FExpressionPart;
 
1826
end;
 
1827
 
 
1828
constructor TGDBExpression.CreateSimple(AText: PChar; ATextLen: Integer);
 
1829
begin
 
1830
  inherited Create;
 
1831
  // not to be parsed
 
1832
  FExpressionPart := nil;
 
1833
  FText.Ptr := AText;
 
1834
  FText.Len := ATextLen;
 
1835
end;
 
1836
 
 
1837
constructor TGDBExpression.Create(AText: PChar; ATextLen: Integer);
 
1838
begin
 
1839
  CreateSimple(AText, ATextLen);
 
1840
  FExpressionPart := ParseExpression(FText.Ptr, FText.Len);
 
1841
end;
 
1842
 
 
1843
constructor TGDBExpression.Create(ATextStr: String);
 
1844
begin
 
1845
  FTextStr := ATextStr;
 
1846
  Create(PChar(FTextStr), length(FTextStr));
 
1847
end;
 
1848
 
 
1849
destructor TGDBExpression.Destroy;
 
1850
begin
 
1851
  FreeAndNil(FExpressionPart);
 
1852
  inherited Destroy;
 
1853
end;
 
1854
 
 
1855
function TGDBExpression.PartCount: Integer;
 
1856
begin
 
1857
  Result := 0;
 
1858
  if FExpressionPart = nil then exit;
 
1859
  if FExpressionPart is TGDBExpressionPartList
 
1860
  then Result := FExpressionPart.PartCount
 
1861
  else Result := 1;
 
1862
end;
 
1863
 
 
1864
function TGDBExpression.IsCommaSeparated: Boolean;
 
1865
begin
 
1866
  Result := (FExpressionPart <> nil) and (FExpressionPart is TGDBExpressionPartCommaList);
 
1867
end;
 
1868
 
 
1869
{ TGDBPTypeRequestCache }
 
1870
 
 
1871
function TGDBPTypeRequestCache.GetRequest(Index: Integer): TGDBPTypeRequest;
 
1872
begin
 
1873
  Result := TGDBPTypeRequestCacheEntry(FList[Index]).FRequest;
 
1874
end;
 
1875
 
 
1876
constructor TGDBPTypeRequestCache.Create;
 
1877
begin
 
1878
  FList := TFPList.Create;
 
1879
end;
 
1880
 
 
1881
destructor TGDBPTypeRequestCache.Destroy;
 
1882
begin
 
1883
  Clear;
 
1884
  inherited Destroy;
 
1885
  FreeAndNil(FList);
 
1886
end;
 
1887
 
 
1888
procedure TGDBPTypeRequestCache.Clear;
 
1889
begin
 
1890
  while FList.Count > 0 do begin
 
1891
    TGDBPTypeRequestCacheEntry(FList[0]).Free;
 
1892
    FList.Delete(0);
 
1893
  end;
 
1894
end;
 
1895
 
 
1896
function TGDBPTypeRequestCache.IndexOf(AThreadId, AStackFrame: Integer;
 
1897
  ARequest: TGDBPTypeRequest): Integer;
 
1898
var
 
1899
  e: TGDBPTypeRequestCacheEntry;
 
1900
begin
 
1901
  Result := FList.Count - 1;
 
1902
  while Result >= 0 do begin
 
1903
    e := TGDBPTypeRequestCacheEntry(FList[Result]);
 
1904
    if (e.ThreadId = AThreadId) and (e.StackFrame = AStackFrame) and
 
1905
       (e.Request.Request =ARequest.Request) and
 
1906
       (e.Request.ReqType =ARequest.ReqType)
 
1907
    then
 
1908
      exit;
 
1909
    dec(Result);
 
1910
  end;
 
1911
end;
 
1912
 
 
1913
procedure TGDBPTypeRequestCache.Add(AThreadId, AStackFrame: Integer;
 
1914
  ARequest: TGDBPTypeRequest);
 
1915
var
 
1916
  e: TGDBPTypeRequestCacheEntry;
 
1917
begin
 
1918
  e := TGDBPTypeRequestCacheEntry.Create;
 
1919
  e.FThreadId := AThreadId;
 
1920
  e.FStackFrame := AStackFrame;
 
1921
  e.FRequest := ARequest;
 
1922
  e.FRequest.Next := nil;
 
1923
  FList.Add(e);
660
1924
end;
661
1925
 
662
1926
{ TGDBPType }
668
1932
  AReq.Error := '';
669
1933
  AReq.Next := FEvalRequest;
670
1934
  FEvalRequest := @AReq;
 
1935
  if FLastEvalRequest = nil then
 
1936
    FLastEvalRequest := @AReq;
 
1937
end;
 
1938
 
 
1939
procedure TGDBType.AddSubType(ASubType: TGDBType);
 
1940
begin
 
1941
  if ASubType.ProcessExpression then
 
1942
    exit;
 
1943
  ASubType.FNextProcessingSubType := FFirstProcessingSubType;
 
1944
  FFirstProcessingSubType := ASubType;
 
1945
end;
 
1946
 
 
1947
function TGDBType.GetIsFinished: Boolean;
 
1948
begin
 
1949
  Result := FProcessState = gtpsFinished;
 
1950
end;
 
1951
 
 
1952
function TGDBType.RequireRequests(ARequired: TGDBTypeProcessRequests; ACustomData: String = ''): Boolean;
 
1953
 
 
1954
  function ApplyBrackets(e: string): string;
 
1955
  var
 
1956
    i: Integer;
 
1957
    f: Boolean;
 
1958
  begin
 
1959
    Result := e;
 
1960
    if (e='') or ( (e[1] = '(') and (e[length(e)] = ')') ) then exit;
 
1961
    f := False;
 
1962
    for i := 1 to length(e) do
 
1963
      f := f or not(e[i] in ['a'..'z', 'A'..'Z', '0'..'9', '_']);
 
1964
    if f then
 
1965
      Result := '(' + Result + ')';
 
1966
  end;
 
1967
 
 
1968
  function GetReqText(AReq: TGDBTypeProcessRequest): String;
 
1969
  begin
 
1970
    case areq of
 
1971
      gptrPTypeExpr:        Result := GdbCmdPType + FExpression;
 
1972
      gptrWhatisExpr:       Result := GdbCmdWhatIs + FExpression;
 
1973
      gptrPTypeOfWhatis:    Result := GdbCmdPType + PCLenToString(FReqResults[gptrWhatisExpr].Result.BaseName);
 
1974
      gptrPTypeExprDeRef:   Result := GdbCmdPType + ApplyBrackets(FExpression) + '^';
 
1975
      gptrPTypeExprDeDeRef: Result := GdbCmdPType + ApplyBrackets(FExpression) + '^^';
 
1976
      gptrEvalExpr:       Result := GdbCmdEvaluate+Quote(FExpression);
 
1977
      gptrEvalExprDeRef:  Result := GdbCmdEvaluate+Quote(FExpression+'^');
 
1978
      gptrEvalExprCast:   Result := GdbCmdEvaluate+Quote(InternalTypeName+'('+FExpression+')');
 
1979
      gptrEvalExpr2:      Result := GdbCmdEvaluate+Quote(ACustomData);
 
1980
      gptrEvalExprDeRef2: Result := GdbCmdEvaluate+Quote(ACustomData+'^');
 
1981
      gptrEvalExprCast2:  Result := GdbCmdEvaluate+Quote(InternalTypeName+'('+ACustomData+')');
 
1982
      gptrPtypeCustomFixCast, gptrPtypeCustomAutoCast, gptrPtypeCustomAutoCast2:
 
1983
                         Result := GdbCmdPType + ACustomData;
 
1984
      gptrInstanceClassName: Result := GdbCmdEvaluate+Quote('(^^^char('+FExpression+')^+3)^');
 
1985
      gptrPtypeCustomEval:   Result := GdbCmdEvaluate+Quote(ACustomData);
 
1986
    end;
 
1987
  end;
 
1988
 
 
1989
var
 
1990
  NeededReq: TGDBTypeProcessRequests;
 
1991
  i: TGDBTypeProcessRequest;
 
1992
begin
 
1993
  NeededReq := ARequired - FProccesReuestsMade;
 
1994
  Result := NeededReq = [];
 
1995
  if Result then exit;
 
1996
 
 
1997
  if (gptrPTypeOfWhatis in NeededReq) and not (gptrWhatisExpr in FProccesReuestsMade)
 
1998
  then begin
 
1999
    Exclude(NeededReq, gptrPTypeOfWhatis);
 
2000
    Include(NeededReq, gptrWhatisExpr);
 
2001
  end;
 
2002
 
 
2003
  FProccesReuestsMade := FProccesReuestsMade + NeededReq;
 
2004
  for i := low(TGDBTypeProcessRequest) to high(TGDBTypeProcessRequest) do
 
2005
    if i in NeededReq then begin
 
2006
      AddTypeReq(FReqResults[i], GetReqText(i));
 
2007
      if i in [gptrEvalExpr, gptrEvalExprDeRef, gptrEvalExprCast, gptrInstanceClassName]
 
2008
      then FReqResults[i].ReqType := gcrtEvalExpr
 
2009
      else FReqResults[i].ReqType := gcrtPType;
 
2010
    end;
 
2011
end;
 
2012
 
 
2013
function TGDBType.IsReqError(AReqType: TGDBTypeProcessRequest; CheckResKind: Boolean = True): Boolean;
 
2014
begin
 
2015
  Result := (not (AReqType in FProccesReuestsMade))
 
2016
         or (FReqResults[AReqType].Error <> '')
 
2017
         or (CheckResKind and (FReqResults[AReqType].Result.Kind = ptprkError));
 
2018
end;
 
2019
 
 
2020
procedure TGDBType.Init;
 
2021
begin
 
2022
  inherited Init;
 
2023
  FProcessState := gtpsFinished;
 
2024
  FParsedExpression := nil;
671
2025
end;
672
2026
 
673
2027
constructor TGDBType.CreateForExpression(const AnExpression: string;
674
 
  const AClassIsPointer: Boolean);
 
2028
  const AFlags: TGDBTypeCreationFlags; AFormat: TWatchDisplayFormat = wdfDefault);
675
2029
begin
676
2030
  Create(skSimple, ''); // initialize
677
2031
  FInternalTypeName := '';
678
2032
  FEvalError := False;
679
2033
  FExpression := AnExpression;
680
 
  FClassIsPointer := AClassIsPointer;
 
2034
  FOrigExpression := FExpression;
 
2035
  FCreationFlags := AFlags;
 
2036
  FExprEvaluateFormat := AFormat;
 
2037
  FEvalStarted := False;
681
2038
  FEvalRequest := nil;
 
2039
  FFirstProcessingSubType := nil;
 
2040
  FNextProcessingSubType := nil;
682
2041
  FProcessState := gtpsInitial;
 
2042
  FHasExprEvaluatedAsText := False;
 
2043
  FHasAutoTypeCastFix := False;
 
2044
  FAutoTypeCastName := '';
 
2045
  FArrayIndexValueLimit := 5;
 
2046
end;
 
2047
 
 
2048
destructor TGDBType.Destroy;
 
2049
var
 
2050
  i: Integer;
 
2051
begin
 
2052
  inherited Destroy;
 
2053
  FreeAndNil(FTypeInfoAncestor);
 
2054
  for i := 0 to Length(FArrayIndexValues) - 1 do
 
2055
    FArrayIndexValues[i].Free;
 
2056
  FArrayIndexValues := nil;
 
2057
  FreeAndNil(FParsedExpression);
683
2058
end;
684
2059
 
685
2060
function TGDBType.ProcessExpression: Boolean;
686
2061
var
687
2062
  Lines: TStringList;
 
2063
  procedure ProcessInitial; forward;
 
2064
  procedure ProcessInitialSimple; forward;
 
2065
  procedure ProcessSimplePointer; forward;
 
2066
 
688
2067
 
689
2068
  function ClearAmpersand(s: string): string;
690
2069
  var i: Integer;
694
2073
    if i > 0 then delete(Result, i, 1);
695
2074
  end;
696
2075
 
 
2076
  procedure SetTypNameFromReq(AReqType: TGDBTypeProcessRequest;
 
2077
    AnUseBaseName: Boolean = False; ADefaultName: String = '');
 
2078
  begin
 
2079
    if IsReqError(AReqType) or (FReqResults[AReqType].Result.BaseName.Len = 0)
 
2080
    then AReqType := gptrPTypeExpr;
 
2081
 
 
2082
    if AnUseBaseName
 
2083
    then FTypeName := PCLenToString(FReqResults[AReqType].Result.BaseName)
 
2084
    else FTypeName := ClearAmpersand(PCLenToString(FReqResults[AReqType].Result.Name));
 
2085
 
 
2086
    if FTypeName = ''
 
2087
    then FTypeName := ADefaultName;
 
2088
    FInternalTypeName := FTypeName;
 
2089
  end;
 
2090
 
697
2091
  Procedure InitLinesFrom(AReq: TGDBPTypeRequest);
698
2092
  begin
699
2093
    FreeAndNil(Lines);
707
2101
  begin
708
2102
    FKind := skEnum;
709
2103
 
710
 
    S := PCLenToString(FPTypeExprReq.Result.Declaration);
 
2104
    S := PCLenToString(FReqResults[gptrPTypeExpr].Result.Declaration);
711
2105
    S := GetPart(['('], [')'], S);
712
2106
    if (S = '') or (S = '...') then
713
2107
      exit;
722
2116
  begin
723
2117
    FKind := skProcedure;
724
2118
 
725
 
    S := PCLenToString(FPTypeExprReq.Result.Declaration);
 
2119
    S := PCLenToString(FReqResults[gptrPTypeExpr].Result.Declaration);
726
2120
    S := GetPart(['('], [')'], S);
727
2121
    if (S = '') then
728
2122
      exit;
736
2130
  begin
737
2131
    FKind := skFunction;
738
2132
 
739
 
    S := PCLenToString(FPTypeExprReq.Result.Declaration);
 
2133
    S := PCLenToString(FReqResults[gptrPTypeExpr].Result.Declaration);
740
2134
    S := GetPart(['('], [')'], S);
741
2135
    if (S = '') then
742
2136
      exit;
743
2137
 
744
2138
    FArguments := TGDBTypes.CreateFromCSV(S);
745
2139
 
746
 
    S := PCLenToString(FPTypeExprReq.Result.Declaration);
 
2140
    S := PCLenToString(FReqResults[gptrPTypeExpr].Result.Declaration);
747
2141
    FResult := TGDBType.Create(skSimple, GetPart([' : '], [], S));
748
2142
  end;
749
2143
 
753
2147
  begin
754
2148
    FKind := skSet;
755
2149
 
756
 
    S := PCLenToString(FPTypeExprReq.Result.Declaration);
 
2150
    S := PCLenToString(FReqResults[gptrPTypeExpr].Result.Declaration);
757
2151
    S := GetPart(['('], [')'], S);
758
2152
    if (S = '') or (S = '...') then
759
2153
      exit;
781
2175
      FKind := skRecord;
782
2176
 
783
2177
    FFields := TDBGFields.Create;
784
 
    InitLinesFrom(FPTypeExprReq);
 
2178
    InitLinesFrom(FReqResults[gptrPTypeExpr]);
785
2179
 
786
2180
    //concatenate all lines and skip last end
787
2181
    for n := 1 to Lines.Count - 2 do begin
801
2195
  {%region    * Class * }
802
2196
  procedure DoClass;
803
2197
  var
804
 
    n: Integer;
805
 
    S: String;
 
2198
    n, i: Integer;
 
2199
    S, S2: String;
806
2200
 
807
2201
    Name: String;
808
2202
    DBGType: TDBGType;
811
2205
  begin
812
2206
    include(FAttributes, saInternalPointer);
813
2207
    FKind := skClass;
814
 
    InitLinesFrom(FPTypeExprReq);
 
2208
    InitLinesFrom(FReqResults[gptrPTypeExpr]);
815
2209
    FFields := TDBGFields.Create;
816
2210
    if Lines.Count < 1 then exit;
817
2211
    s := Lines[0];
818
2212
    FAncestor := GetPart([': public '], [' '], s);
819
2213
 
820
2214
    Location := flPublished;
821
 
    for n := 1 to Lines.Count - 2 do
 
2215
    n := 0;
 
2216
    while n <  Lines.Count - 2 do
822
2217
    begin
 
2218
      inc(n);
823
2219
      S := Lines[n];
824
 
      if S = '' then Continue;
 
2220
      if S = '' then Continue; // TODO: clear location (private, peblic)
 
2221
      if S = 'end' then break;
825
2222
      if S = '  private' then Location := flPrivate
826
2223
      else if S = '  protected' then Location := flProtected
827
2224
      else if S = '  public' then Location := flPublic
828
2225
      else if S = '  published' then Location := flPublished
829
2226
      else begin
830
2227
        Flags := [];
831
 
        if Pos(' procedure ', S) > 0
 
2228
        if Pos('  procedure ', S) > 0
832
2229
        then begin
833
2230
          Name := GetPart(['procedure '], [' ', ';'], S);
834
2231
          DBGType := TGDBType.Create(
838
2235
          if GetPart(['; '], [';'], S) = 'virtual'
839
2236
          then Flags := [ffVirtual];
840
2237
        end
841
 
        else if Pos(' destructor  ~', S) > 0
 
2238
        else if Pos('  destructor  ~', S) > 0
842
2239
        then begin
843
2240
          Name := GetPart(['destructor  ~'], [' ', ';'], S);
844
2241
          DBGType := TGDBType.Create(
849
2246
          then Flags := [ffVirtual];
850
2247
          Include(Flags, ffDestructor);
851
2248
        end
852
 
        else if Pos(' constructor ', S) > 0
 
2249
        else if Pos('  constructor ', S) > 0
853
2250
        then begin
854
2251
          Name := GetPart(['constructor '], [' ', ';'], S);
855
2252
          DBGType := TGDBType.Create(
861
2258
          then Flags := [ffVirtual];
862
2259
          Include(Flags, ffConstructor);
863
2260
        end
864
 
        else if Pos(' function ', S) > 0
 
2261
        else if Pos('  function ', S) > 0
865
2262
        then begin
866
2263
          Name := GetPart(['function  '], [' ', ';'], S);
867
2264
          DBGType := TGDBType.Create(
874
2271
        end
875
2272
        else begin
876
2273
          Name := GetPart(['    '], [' '], S);
877
 
          DBGType := TGDBType.Create(skSimple, GetPart([' : '], [';'], S));
 
2274
          S2 := GetPart([' : '], [';'], S);
 
2275
          if (lowercase(copy(S2, 1, 7)) = 'record ') then begin
 
2276
            i := 1;
 
2277
            while (n <  Lines.Count - 2) and (i > 0) do
 
2278
            begin
 
2279
              inc(n);
 
2280
              S := Lines[n];
 
2281
              if S = '' then Continue;
 
2282
              if pos(': record ', S) > 0 then inc(i);
 
2283
              if pos(' end;', S) > 0 then dec(i);
 
2284
              S2 := S2 + ' ' + Trim(S);
 
2285
            end;
 
2286
          end;
 
2287
          DBGType := TGDBType.Create(skSimple, S2);
878
2288
        end;
879
 
 
880
 
        FFields.Add(TDBGField.Create(Name, DBGType, Location, Flags));
 
2289
        FFields.Add(TDBGField.Create(Name, DBGType, Location, Flags, FTypeName));
881
2290
      end;
882
2291
    end;
883
2292
  end;
884
2293
 
885
 
  procedure ProcessClassNamePType;
886
 
  begin
887
 
    // Stabs
888
 
      FTypeName := ClearAmpersand(PCLenToString(FWhatIsExprReq.Result.Name));
889
 
      FInternalTypeName := FTypeName;
890
 
 
891
 
    if (FExtraReq.Error <> '') or (FExtraReq.Result.Kind = ptprkError)
892
 
    or (FExtraReq.Result.BaseName.Len = 0)
893
 
    then begin
894
 
      // FExtraReq failed;
895
 
      debugln('Failed "PTYPE" request for class type name');
896
 
      DoClass
897
 
    end
898
 
    else
899
 
    if (not (ptprfPointer in FExtraReq.Result.Flags))
900
 
    then begin
901
 
      // Actual Class, Not a pointer
902
 
      DoClass
903
 
    end
904
 
    else begin
905
 
      // Pointer
906
 
      FKind := skPointer;
907
 
    end;
908
 
    Result := True;
909
 
    // ====> DONE
910
 
  end;
911
 
 
912
 
  procedure ProcessClassNameWhatIs;
913
 
  begin
914
 
    // Dwarf, Classes are always pointer
915
 
    FTypeName := ClearAmpersand(PCLenToString(FWhatIsExprReq.Result.Name));
916
 
    FInternalTypeName := FTypeName;
917
 
 
918
 
    if (FExtraReq.Error <> '') or (FExtraReq.Result.Kind = ptprkError)
919
 
    or (FExtraReq.Result.BaseName.Len = 0)
920
 
    then begin
921
 
      // FExtraReq failed;
922
 
      debugln('Failed "WHATIS" request for class type name');
923
 
      DoClass
924
 
    end
925
 
    else
926
 
    // dwarf, expect always pointer, but may have " = class"
927
 
    if (not (ptprfPointer in FExtraReq.Result.Flags))
928
 
    or (FExtraReq.Result.Kind = ptprkClass)
929
 
    then begin
930
 
      // Actual Class, Not a pointer
931
 
      DoClass
932
 
    end
933
 
    else begin
934
 
      // Pointer
935
 
      FKind := skPointer;
936
 
    end;
937
 
    Result := True;
938
 
    // ====> DONE
939
 
  end;
940
 
 
941
 
  procedure ProcessClassWhatIs;
942
 
  begin
943
 
    if (FWhatIsExprReq.Error <> '') or (FWhatIsExprReq.Result.Kind = ptprkError)
944
 
    or (FWhatIsExprReq.Result.BaseName.Len = 0)
945
 
    then begin
946
 
      // failed to get a classname => assume class
947
 
      debugln('Failed "WHATIS" request for class expression');
948
 
      FTypeName := PCLenToString(FPTypeExprReq.Result.BaseName);
949
 
      FInternalTypeName := FTypeName;
 
2294
  procedure ProcessClassPointer;
 
2295
  begin
 
2296
    FProcessState := gtpsClassPointer;
 
2297
    if not RequireRequests([gptrWhatisExpr]) then
 
2298
      exit;
 
2299
 
 
2300
      FKind := skPointer;
 
2301
      SetTypNameFromReq(gptrWhatisExpr);
 
2302
      Result := True;
 
2303
      // ====> DONE
 
2304
  end;
 
2305
 
 
2306
  procedure ProcessClassAncestor;
 
2307
  var
 
2308
    i: Integer;
 
2309
  begin
 
2310
    FProcessState := gtpsClassAncestor;
 
2311
 
 
2312
    If FTypeInfoAncestor = nil then begin
 
2313
      FTypeInfoAncestor := TGDBType.CreateForExpression(FAncestor,
 
2314
        FCreationFlags*[gtcfClassIsPointer, gtcfFullTypeInfo, gtcfSkipTypeName] + [gtcfExprIsType]
 
2315
      );
 
2316
      AddSubType(FTypeInfoAncestor);
 
2317
    end;
 
2318
    if not FTypeInfoAncestor.IsFinished then
 
2319
      exit;
 
2320
 
 
2321
    // add ancestor
 
2322
    if FTypeInfoAncestor.FFields <> nil then
 
2323
      for i := 0 to FTypeInfoAncestor.FFields.Count - 1 do
 
2324
        FFields.Add(FTypeInfoAncestor.FFields[i]);
 
2325
    Result := True;
 
2326
  end;
 
2327
 
 
2328
  procedure FinishProcessClass;
 
2329
  begin
 
2330
    FProcessState := gtpsFinishProcessClass;
 
2331
    if (gtcfFullTypeInfo in FCreationFlags) and  not (gtcfExprIsType in FCreationFlags) then
 
2332
      if not RequireRequests([gptrWhatisExpr]) then
 
2333
        exit;
 
2334
 
 
2335
    // Handle Error in ptype^ as normal class
 
2336
    // May need a whatis, if aliased names are needed "type TFooAlias = type TFoo"
 
2337
    SetTypNameFromReq(gptrWhatisExpr, True);
 
2338
    DoClass;
 
2339
    if (gtcfFullTypeInfo in FCreationFlags) and (FAncestor <> '')
 
2340
    then ProcessClassAncestor
 
2341
    else Result := True; // ====> DONE
 
2342
  end;
 
2343
 
 
2344
  procedure ProcessClass;
 
2345
  var
 
2346
    t: TGDBTypeProcessRequest;
 
2347
    ResultList: TGDBMINameValueList;
 
2348
    s: String;
 
2349
    i: Integer;
 
2350
  begin
 
2351
    FProcessState := gtpsClass;
 
2352
 
 
2353
    if (gtcfExprIsType in FCreationFlags) then begin
 
2354
      SetTypNameFromReq(gptrPTypeExpr, True);
950
2355
      DoClass;
951
 
      Result := True;
952
 
      // ====> DONE
 
2356
      if (gtcfFullTypeInfo in FCreationFlags) and (FAncestor <> '')
 
2357
      then ProcessClassAncestor
 
2358
      else Result := True; // ====> DONE
953
2359
      exit;
954
2360
    end;
955
2361
 
956
 
    if (ptprfParamByRef in FWhatIsExprReq.Result.Flags) then
957
 
      include(FAttributes, saRefParam);
958
 
 
959
 
    if (ptprfPointer in FWhatIsExprReq.Result.Flags)
960
 
    and (FWhatIsExprReq.Result.Kind = ptprkSimple) // Typename alias, must be simple
 
2362
    if saRefParam in FAttributes
 
2363
    then t := gptrPTypeExprDeDeRef  // &Class (var param; dwarf)
 
2364
    else t := gptrPTypeExprDeRef;   // Class
 
2365
 
 
2366
    if not RequireRequests([gptrPTypeExpr, t])
 
2367
    then exit;
 
2368
 
 
2369
    if IsReqError(t)
 
2370
    then debugln('Failed "ptype expr^[^]" request for class expression');
 
2371
 
 
2372
    if (not IsReqError(t)) and (ptprfPointer in FReqResults[t].Result.Flags)
961
2373
    then begin
962
 
      // pointer to class
963
 
      FKind := skPointer;
964
 
      FTypeName := ClearAmpersand(PCLenToString(FWhatIsExprReq.Result.Name));
965
 
      FInternalTypeName := FTypeName;
966
 
      Result := True;
967
 
      // ====> DONE
 
2374
      ProcessClassPointer;
968
2375
      exit;
969
 
    end;
970
 
 
971
 
    if FClassIsPointer then begin
972
 
      // Dwarf, Classes are always pointer      // need Whatis <type>
973
 
      AddTypeReq(FExtraReq, 'whatis ' + PCLenToString(FWhatIsExprReq.Result.BaseName));
974
 
      FProcessState := gtpsClassNameWhatIs;
975
 
      // ====> state = ClassNameWhats
976
2376
    end
977
2377
    else begin
978
 
      // Stabs        // need PType <type>
979
 
      AddTypeReq(FExtraReq, 'ptype ' + PCLenToString(FWhatIsExprReq.Result.BaseName));
980
 
        FProcessState := gtpsClassNamePType;
981
 
        // ====> state = ClassNamePType
982
 
    end;
 
2378
      // before type cast
 
2379
      FTypeDeclaration := PCLenToString(FReqResults[gptrPTypeExpr].Result.BaseName);
 
2380
 
 
2381
      if (gtcfAutoCastClass in FCreationFlags) then begin
 
2382
        if not RequireRequests([gptrInstanceClassName]) then
 
2383
          exit;
 
2384
        if not IsReqError(gptrInstanceClassName) then begin
 
2385
          ResultList := TGDBMINameValueList.Create(FReqResults[gptrInstanceClassName].Result.GdbDescription);
 
2386
          s := ParseGDBString(ResultList.Values['value']);
 
2387
          ResultList.Free;
 
2388
          if s <> ''
 
2389
          then i := ord(s[1])
 
2390
          else i := 1;
 
2391
          if i <= length(s)-1 then begin
 
2392
            FAutoTypeCastName := copy(s, 2, i);
 
2393
            RequireRequests([gptrPtypeCustomAutoCast], FAutoTypeCastName);
 
2394
            FProcessState := gtpsClassAutoCast;
 
2395
            exit;
 
2396
          end;
 
2397
          // continue without type cast
 
2398
        end;
 
2399
      end;
 
2400
 
 
2401
      FinishProcessClass;
 
2402
    end;
 
2403
  end;
 
2404
 
 
2405
  procedure ProcessClassAutoCast;
 
2406
  var
 
2407
    s: String;
 
2408
  begin
 
2409
    if IsReqError(gptrPtypeCustomAutoCast) or
 
2410
       (not(FReqResults[gptrPtypeCustomAutoCast].Result.Kind = ptprkClass)) or
 
2411
       (LowerCase(FAutoTypeCastName) = LowerCase(PCLenToString(FReqResults[gptrPTypeExpr].Result.BaseName))) // don't typecast to itself
 
2412
    then begin
 
2413
      FinishProcessClass; // normal class finish
 
2414
      exit;
 
2415
    end;
 
2416
 
 
2417
    s := FAutoTypeCastName + '(' + FExpression + ')';
 
2418
    if not RequireRequests([gptrPtypeCustomAutoCast2], s)
 
2419
    then exit;
 
2420
 
 
2421
    if FHasAutoTypeCastFix
 
2422
    then s := '^' + s;
 
2423
 
 
2424
    if IsReqError(gptrPtypeCustomAutoCast2) and (not FHasAutoTypeCastFix)
 
2425
    then begin
 
2426
      s := '^' + s;
 
2427
      FHasAutoTypeCastFix := True;
 
2428
      exclude(FProccesReuestsMade, gptrPtypeCustomAutoCast2);
 
2429
      RequireRequests([gptrPtypeCustomAutoCast2], s);
 
2430
      exit;
 
2431
    end;
 
2432
 
 
2433
    if IsReqError(gptrPtypeCustomAutoCast2) or
 
2434
       not(FReqResults[gptrPtypeCustomAutoCast2].Result.Kind = ptprkClass)
 
2435
    then begin
 
2436
      FinishProcessClass; // normal class finish
 
2437
      exit;
 
2438
    end;
 
2439
 
 
2440
    FExpression := s;
 
2441
    FReqResults[gptrPTypeExpr] := FReqResults[gptrPtypeCustomAutoCast2];
 
2442
    exclude(FProccesReuestsMade, gptrWhatisExpr);
 
2443
    FinishProcessClass;
983
2444
  end;
984
2445
  {%endregion    * Class * }
985
2446
 
 
2447
  {%region    * Array * }
 
2448
  procedure ProcessArray;
 
2449
  var
 
2450
    PTypeResult: TGDBPTypeResult;
 
2451
  begin
 
2452
    FProcessState := gtpsArray;
 
2453
 
 
2454
    PTypeResult := FReqResults[gptrPTypeExpr].Result;
 
2455
    // In DWARF, some Dynamic Array, are pointer to there base type
 
2456
    if (ptprfPointer in PTypeResult.Flags) and (PTypeResult.Kind =ptprkSimple)
 
2457
    then begin
 
2458
      if not RequireRequests([gptrPTypeExprDeRef])
 
2459
      then exit;
 
2460
      if (not IsReqError(gptrPTypeExprDeRef)) then
 
2461
      PTypeResult := FReqResults[gptrPTypeExprDeRef].Result;
 
2462
      // This implies it is an internal pointer
 
2463
      if (ptprfDynArray in PTypeResult.Flags)
 
2464
      then include(FAttributes, saInternalPointer);
 
2465
    end;
 
2466
 
 
2467
    if (PTypeResult.Flags * [ptprfDynArray, ptprfPointer] =  [ptprfDynArray, ptprfPointer])
 
2468
    then include(FAttributes, saInternalPointer);
 
2469
 
 
2470
    if (saInternalPointer in FAttributes) then begin
 
2471
      if not RequireRequests([gptrPTypeExprDeRef])
 
2472
      then exit;
 
2473
    end;
 
2474
 
 
2475
    if (saInternalPointer in FAttributes) and (not IsReqError(gptrPTypeExprDeRef)) then
 
2476
      PTypeResult := FReqResults[gptrPTypeExprDeRef].Result
 
2477
    else
 
2478
      PTypeResult := FReqResults[gptrPTypeExpr].Result;
 
2479
 
 
2480
    if ptprfPointer in PTypeResult.Flags then begin
 
2481
      ProcessSimplePointer;
 
2482
      exit;
 
2483
    end;
 
2484
 
 
2485
    FKind := skSimple;
 
2486
    if (ptprfDynArray in PTypeResult.Flags)
 
2487
    then include(FAttributes, saDynArray)
 
2488
    else include(FAttributes, saArray);
 
2489
 
 
2490
    if not(gtcfSkipTypeName in FCreationFlags) then begin
 
2491
      if not RequireRequests([gptrWhatisExpr])
 
2492
      then exit;
 
2493
      SetTypNameFromReq(gptrWhatisExpr, True);
 
2494
    end;
 
2495
 
 
2496
    FTypeDeclaration := ClearAmpersand(PCLenToString(PTypeResult.Declaration));
 
2497
    Result := True;
 
2498
    // ====> DONE
 
2499
  end;
 
2500
  {%endregion    * Array * }
 
2501
 
986
2502
  {%region    * Simple * }
987
2503
  procedure ProcessSimplePointer;
988
2504
  begin
 
2505
    FProcessState := gtpsSimplePointer;
 
2506
    // there may be multiply levels of pointer, get the name of this pointer
 
2507
    if not RequireRequests([gptrPTypeExpr, gptrWhatisExpr])
 
2508
    then exit;
 
2509
 
989
2510
    FKind := skPointer;
990
 
    if (FWhatIsExprReq.Error = '') and (FWhatIsExprReq.Result.Kind = ptprkSimple) then begin
 
2511
    if not IsReqError(gptrWhatisExpr) and (FReqResults[gptrWhatisExpr].Result.Kind = ptprkSimple)
 
2512
    then begin
991
2513
      // Whatis result is ok
992
 
      if (ptprfParamByRef in FWhatIsExprReq.Result.Flags) then
 
2514
      if (ptprfParamByRef in FReqResults[gptrWhatisExpr].Result.Flags) then
993
2515
        include(FAttributes, saRefParam);
994
 
      FTypeName := ClearAmpersand(PCLenToString(FWhatIsExprReq.Result.Name));
 
2516
      SetTypNameFromReq(gptrWhatisExpr);
995
2517
    end
996
2518
    else begin
997
2519
      // Whatis result failed
998
 
      FTypeName := ClearAmpersand((PCLenToString(FPTypeExprReq.Result.Name)));
 
2520
      SetTypNameFromReq(gptrPTypeExpr);
999
2521
    end;
1000
 
    FInternalTypeName := FTypeName;
1001
2522
    Result := True;
1002
2523
    // ====> DONE
1003
2524
  end;
1004
2525
  {%endregion    * Simple * }
1005
2526
 
1006
 
  procedure ProcessInitialPType;
1007
 
  begin
1008
 
    if FPTypeExprReq.Error <> '' then begin
 
2527
  {%region    * EvaluateExpression * }
 
2528
  function GetParsedFromResult(AGdbDesc, AField: String): String;
 
2529
  var
 
2530
    ResultList: TGDBMINameValueList;
 
2531
  begin
 
2532
    ResultList := TGDBMINameValueList.Create(AGdbDesc);
 
2533
    Result := ResultList.Values[AField];
 
2534
    //FTextValue := DeleteEscapeChars(FTextValue);
 
2535
    ResultList.Free;
 
2536
  end;
 
2537
  procedure ParseFromResult(AGdbDesc, AField: String);
 
2538
  begin
 
2539
    FExprEvaluatedAsText := GetParsedFromResult(AGdbDesc, AField);
 
2540
    FHasExprEvaluatedAsText := True;
 
2541
  end;
 
2542
  procedure ParseFromResultForStrFixed(AGdbDesc, AField: String);
 
2543
  begin
 
2544
    FStringExprEvaluatedAsText := GetParsedFromResult(AGdbDesc, AField);
 
2545
    FHasStringExprEvaluatedAsText := True;
 
2546
  end;
 
2547
 
 
2548
  procedure EvaluateExpressionDynArrayGetData;
 
2549
  var
 
2550
    i, m: Integer;
 
2551
    s: String;
 
2552
  begin
 
2553
    FProcessState := gtpsEvalExprDynArrayGetData;
 
2554
 
 
2555
    if (FLen <= 0) or (FArrayIndexValueLimit <= 0) then begin
 
2556
      Result := True;
 
2557
      exit;
 
2558
    end;
 
2559
 
 
2560
    if (Length(FArrayIndexValues) > 0) then begin
 
2561
      FExprEvaluatedAsText := '';
 
2562
      for i := 0 to Length(FArrayIndexValues) - 1 do begin
 
2563
        s := FArrayIndexValues[i].ExprEvaluatedAsText;
 
2564
        if (pos(' ', s) > 0) or (pos(',', s) > 0) then
 
2565
          s := '('+s+')';
 
2566
        if i > 0 then
 
2567
          FExprEvaluatedAsText := FExprEvaluatedAsText + ', ';
 
2568
        FExprEvaluatedAsText := FExprEvaluatedAsText + s;
 
2569
      end;
 
2570
      if FArrayIndexValueLimit < FLen then
 
2571
        FExprEvaluatedAsText := FExprEvaluatedAsText + ', ...';
 
2572
 
 
2573
      Result := True;
 
2574
      exit;
 
2575
    end;
 
2576
 
 
2577
    if (FExprEvaluatedAsText <> '') and
 
2578
       (FExprEvaluatedAsText[1] = '{')   // gdb returned array data
 
2579
    then begin
 
2580
      if (FLen = 0) or
 
2581
         ((Length(FExprEvaluatedAsText) > 1) and (FExprEvaluatedAsText[2] <> '}') )
 
2582
      then begin
 
2583
        Result := True;
 
2584
        exit;
 
2585
      end;
 
2586
    end;
 
2587
 
 
2588
    // Get Data
 
2589
    m := Min(FArrayIndexValueLimit, FLen);
 
2590
    SetLength(FArrayIndexValues, m);
 
2591
    for i := 0 to m-1 do begin
 
2592
      FArrayIndexValues[i] := TGDBType.CreateForExpression(FExpression+'['+IntToStr(i)+']',
 
2593
        FCreationFlags + [gtcfExprEvaluate]);
 
2594
      if i = 0
 
2595
      then FArrayIndexValues[i].FArrayIndexValueLimit := FArrayIndexValueLimit - 2
 
2596
      else FArrayIndexValues[i].FArrayIndexValueLimit := FArrayIndexValueLimit - 3;
 
2597
      AddSubType(FArrayIndexValues[i]);
 
2598
    end;
 
2599
  end;
 
2600
 
 
2601
  procedure EvaluateExpressionDynArray;
 
2602
  begin
 
2603
    FProcessState := gtpsEvalExprDynArray;
 
2604
    if FExprEvaluateFormat <> wdfDefault then begin;
 
2605
      Result := True;
 
2606
      exit;
 
2607
    end;
 
2608
 
 
2609
 
 
2610
    FBoundLow :=  -1;
 
2611
    FBoundHigh := -1;
 
2612
    FLen := -1;
 
2613
 
 
2614
    if not RequireRequests([gptrPtypeCustomEval], '^^longint('+FExpression+')[-1]') then exit;
 
2615
    if not IsReqError(gptrPtypeCustomEval, False) then begin
 
2616
      FBoundLow :=  0;
 
2617
      FBoundHigh  := StrToIntDef(GetParsedFromResult(FReqResults[gptrPtypeCustomEval].Result.GdbDescription, 'value'), -1);
 
2618
      FLen := FBoundHigh + 1;
 
2619
    end;
 
2620
 
 
2621
    if (saInternalPointer in FAttributes) then begin
 
2622
      if not RequireRequests([gptrEvalExprDeRef]) then exit;
 
2623
      if not IsReqError(gptrEvalExprDeRef, False) then begin
 
2624
        ParseFromResult(FReqResults[gptrEvalExprDeRef].Result.GdbDescription, 'value');
 
2625
        EvaluateExpressionDynArrayGetData;
 
2626
        exit;
 
2627
      end;
 
2628
    end;
 
2629
 
 
2630
    if (saRefParam in FAttributes) then begin
 
2631
      if not RequireRequests([gptrEvalExprCast]) then exit;
 
2632
      if not IsReqError(gptrEvalExprCast, False) then begin
 
2633
        ParseFromResult(FReqResults[gptrEvalExprCast].Result.GdbDescription, 'value');
 
2634
        EvaluateExpressionDynArrayGetData;
 
2635
        exit;
 
2636
      end;
 
2637
    end;
 
2638
 
 
2639
    if not RequireRequests([gptrEvalExpr]) then exit;
 
2640
    if not IsReqError(gptrEvalExpr, False) then begin
 
2641
      ParseFromResult(FReqResults[gptrEvalExpr].Result.GdbDescription, 'value');
 
2642
      EvaluateExpressionDynArrayGetData;
 
2643
      exit;
 
2644
    end;
 
2645
 
 
2646
    if FLen > 0 then begin
 
2647
      EvaluateExpressionDynArrayGetData;
 
2648
      exit;
 
2649
    end;
 
2650
 
 
2651
    // TODO: set Validity = error
 
2652
    ParseFromResult(FReqResults[gptrEvalExpr].Result.GdbDescription, 'msg');
 
2653
    Result := True;
 
2654
  end;
 
2655
 
 
2656
  procedure EvaluateExpressionArray;
 
2657
  var
 
2658
    PTypeResult: TGDBPTypeResult;
 
2659
  begin
 
2660
    FProcessState := gtpsEvalExprArray;
 
2661
    if FExprEvaluateFormat <> wdfDefault then begin;
 
2662
      Result := True;
 
2663
      exit;
 
2664
    end;
 
2665
 
 
2666
    PTypeResult := FReqResults[gptrPTypeExpr].Result;
 
2667
    FBoundLow :=  PCLenToInt(PTypeResult.BoundLow);
 
2668
    FBoundHigh := PCLenToInt(PTypeResult.BoundHigh);
 
2669
    FLen := PCLenToInt(PTypeResult.BoundHigh) - PCLenToInt(PTypeResult.BoundLow) + 1;
 
2670
 
 
2671
 
 
2672
    if (saInternalPointer in FAttributes) then begin
 
2673
      if not RequireRequests([gptrEvalExprDeRef]) then exit;
 
2674
      if not IsReqError(gptrEvalExprDeRef, False) then begin
 
2675
        ParseFromResult(FReqResults[gptrEvalExprDeRef].Result.GdbDescription, 'value');
 
2676
        Result := True;
 
2677
        exit;
 
2678
      end;
 
2679
    end;
 
2680
 
 
2681
    if (saRefParam in FAttributes) then begin
 
2682
      if not RequireRequests([gptrEvalExprCast]) then exit;
 
2683
      if not IsReqError(gptrEvalExprCast, False) then begin
 
2684
        ParseFromResult(FReqResults[gptrEvalExprCast].Result.GdbDescription, 'value');
 
2685
        Result := True;
 
2686
        exit;
 
2687
      end;
 
2688
    end;
 
2689
 
 
2690
    if not RequireRequests([gptrEvalExpr]) then exit;
 
2691
    if not IsReqError(gptrEvalExpr, False) then begin
 
2692
      ParseFromResult(FReqResults[gptrEvalExpr].Result.GdbDescription, 'value');
 
2693
      Result := True;
 
2694
      exit;
 
2695
    end;
 
2696
 
 
2697
    // TODO: set Validity = error
 
2698
    ParseFromResult(FReqResults[gptrEvalExpr].Result.GdbDescription, 'msg');
 
2699
    Result := True;
 
2700
  end;
 
2701
 
 
2702
  procedure EvaluateExpression;
 
2703
  begin
 
2704
    FProcessState := gtpsEvalExpr;
 
2705
 
 
2706
    if not(gtcfExprEvaluate in FCreationFlags) then begin
 
2707
      Result := True;
 
2708
      exit;
 
2709
    end;
 
2710
 
 
2711
    if saDynArray in FAttributes then begin
 
2712
      EvaluateExpressionDynArray;
 
2713
      exit;
 
2714
    end;
 
2715
    if saArray in FAttributes then begin
 
2716
      EvaluateExpressionArray;
 
2717
      exit;
 
2718
    end;
 
2719
 
 
2720
    if FExprEvaluateFormat <> wdfDefault then begin;
 
2721
      Result := True;
 
2722
      exit;
 
2723
    end;
 
2724
 
 
2725
    // TODO: stringFixed need to know about:
 
2726
    // - AutoTypeCast
 
2727
 
 
2728
    if (saInternalPointer in FAttributes) then begin
 
2729
      if not RequireRequests([gptrEvalExprDeRef]) then exit;
 
2730
      if not IsReqError(gptrEvalExprDeRef, False) then begin
 
2731
        ParseFromResult(FReqResults[gptrEvalExprDeRef].Result.GdbDescription, 'value');
 
2732
 
 
2733
        if (gtcfExprEvalStrFixed in FCreationFlags) and
 
2734
           (FParsedExpression <> nil) and FParsedExpression.MayNeedStringFix
 
2735
        then begin
 
2736
          if not RequireRequests([gptrEvalExprDeRef2], FParsedExpression.TextStrFixed) then exit;
 
2737
          ParseFromResultForStrFixed(FReqResults[gptrEvalExprDeRef2].Result.GdbDescription, 'value');
 
2738
        end;
 
2739
 
 
2740
        Result := True;
 
2741
        exit;
 
2742
      end;
 
2743
    end;
 
2744
 
 
2745
    if (saRefParam in FAttributes) then begin
 
2746
      if not RequireRequests([gptrEvalExprCast]) then exit;
 
2747
      if not IsReqError(gptrEvalExprCast, False) then begin
 
2748
        ParseFromResult(FReqResults[gptrEvalExprCast].Result.GdbDescription, 'value');
 
2749
 
 
2750
        if (gtcfExprEvalStrFixed in FCreationFlags) and
 
2751
           (FParsedExpression <> nil) and FParsedExpression.MayNeedStringFix
 
2752
        then begin
 
2753
          if not RequireRequests([gptrEvalExprCast2], FParsedExpression.TextStrFixed) then exit;
 
2754
          ParseFromResultForStrFixed(FReqResults[gptrEvalExprCast2].Result.GdbDescription, 'value');
 
2755
        end;
 
2756
 
 
2757
        Result := True;
 
2758
        exit;
 
2759
      end;
 
2760
    end;
 
2761
 
 
2762
    if not RequireRequests([gptrEvalExpr]) then exit;
 
2763
    if not IsReqError(gptrEvalExpr, False) then begin
 
2764
      ParseFromResult(FReqResults[gptrEvalExpr].Result.GdbDescription, 'value');
 
2765
 
 
2766
      if (gtcfExprEvalStrFixed in FCreationFlags) and
 
2767
         (FParsedExpression <> nil) and FParsedExpression.MayNeedStringFix
 
2768
      then begin
 
2769
        if not RequireRequests([gptrEvalExpr2], FParsedExpression.TextStrFixed) then exit;
 
2770
        ParseFromResultForStrFixed(FReqResults[gptrEvalExpr2].Result.GdbDescription, 'value');
 
2771
      end;
 
2772
 
 
2773
      Result := True;
 
2774
      exit;
 
2775
    end;
 
2776
 
 
2777
    // TODO: set Validity = error
 
2778
    ParseFromResult(FReqResults[gptrEvalExpr].Result.GdbDescription, 'msg');
 
2779
    Result := True;
 
2780
  end;
 
2781
  {%endregion    * EvaluateExpression * }
 
2782
 
 
2783
  procedure ProcessInitialSimple;
 
2784
  var
 
2785
    i: Integer;
 
2786
    PTypeResult: TGDBPTypeResult;
 
2787
  begin
 
2788
    FProcessState := gtpsInitialSimple;
 
2789
 
 
2790
    // TODO: ptype may be known by FParsedExpression
 
2791
    if not RequireRequests([gptrPTypeExpr]) //+wi)
 
2792
    then exit;
 
2793
 
 
2794
    if IsReqError(gptrPTypeExpr) then begin
 
2795
       //Cannot access memory at address 0x0
 
2796
      if (pos('address 0x0', FReqResults[gptrPTypeExpr].Error) > 0) and
 
2797
         FParsedExpression.MayNeedTypeCastFix
 
2798
      then begin
 
2799
        exclude(FProccesReuestsMade, gptrPTypeExpr);
 
2800
        ProcessInitial;
 
2801
        exit;
 
2802
      end;
 
2803
 
1009
2804
      FEvalError := True;
1010
2805
      exit;
1011
2806
    end;
 
2807
    PTypeResult := FReqResults[gptrPTypeExpr].Result;
1012
2808
 
1013
 
    if (ptprfParamByRef in FPTypeExprReq.Result.Flags) then
 
2809
    if (ptprfParamByRef in PTypeResult.Flags) then
1014
2810
      include(FAttributes, saRefParam);
1015
2811
 
1016
 
 
1017
 
    if (ptprfPointer in FPTypeExprReq.Result.Flags)
1018
 
    and ( (FPTypeExprReq.Result.Kind in
1019
 
           [ptprkSimple, ptprkRecord, ptprkEnum, ptprkSet])
1020
 
         or (FClassIsPointer and (FPTypeExprReq.Result.Kind in
1021
 
                                  [ptprkProcedure, ptprkFunction])  )
 
2812
    // In DWARF, some Dynamic Array, are pointer to there base type
 
2813
    if (ptprfPointer in PTypeResult.Flags) and (PTypeResult.Kind =ptprkSimple)
 
2814
    then begin
 
2815
      if not RequireRequests([gptrPTypeExprDeRef])
 
2816
      then exit;
 
2817
      if (not IsReqError(gptrPTypeExprDeRef)) and
 
2818
         (FReqResults[gptrPTypeExprDeRef].Result.Kind = ptprkArray)
 
2819
      then begin
 
2820
        ProcessArray;
 
2821
        exit;
 
2822
      end;
 
2823
    end;
 
2824
 
 
2825
    case PTypeResult.Kind of
 
2826
      //ptprkError: ;
 
2827
      //ptprkSimple: ;
 
2828
      ptprkClass: begin
 
2829
          ProcessClass;
 
2830
          exit;
 
2831
        end;
 
2832
      //ptprkRecord: ;
 
2833
      //ptprkEnum: ;
 
2834
      //ptprkSet: ;
 
2835
      ptprkArray: begin
 
2836
          ProcessArray;
 
2837
          exit;
 
2838
      end;
 
2839
      //ptprkProcedure: ;
 
2840
      //ptprkFunction: ;
 
2841
    end;
 
2842
 
 
2843
    if (ptprfPointer in PTypeResult.Flags)
 
2844
    and ( (PTypeResult.Kind in [ptprkSimple, ptprkRecord, ptprkEnum, ptprkSet])
 
2845
          or ( (gtcfClassIsPointer in FCreationFlags) and
 
2846
               (PTypeResult.Kind in [ptprkProcedure, ptprkFunction])  )
1022
2847
        )
1023
2848
    then begin
1024
 
      // there may be multiply levels of pointer, get the name of this pointer
1025
 
      AddTypeReq(FWhatIsExprReq, 'whatis ' + FExpression);
1026
 
      FProcessState := gtpsSimplePointer;
1027
 
      // ====> state = SimplePointer
 
2849
      ProcessSimplePointer;
1028
2850
      exit;
1029
2851
    end;
1030
2852
 
1031
 
    if (ptprfParamByRef in FPTypeExprReq.Result.Flags)
1032
 
    and not (FPTypeExprReq.Result.Kind in [ptprkError, ptprkClass])
 
2853
    if (ptprfParamByRef in PTypeResult.Flags)
 
2854
    and not (PTypeResult.Kind in [ptprkError])
1033
2855
    then begin
1034
2856
      // could be a pointer // need ptype of whatis
1035
 
      if FProcessState = gtpsInitialPType then begin
1036
 
        AddTypeReq(FWhatIsExprReq, 'whatis ' + FExpression);
1037
 
        FProcessState := gtpsInitialPType2;
1038
 
        // ====> state = gtpsInitialPType2
1039
 
        exit;
1040
 
      end
1041
 
      else if (FProcessState = gtpsInitialPType2) and (FWhatIsExprReq.Result.BaseName.Len > 0)
 
2857
      if not RequireRequests([gptrWhatisExpr])
 
2858
      then exit;
 
2859
 
 
2860
      if (FReqResults[gptrWhatisExpr].Result.BaseName.Len > 0)
1042
2861
      then begin
1043
 
        AddTypeReq(FExtraReq, 'ptype ' + PCLenToString(FWhatIsExprReq.Result.BaseName));
1044
 
        FProcessState := gtpsInitialPType3;
1045
 
        // ====> state = gtpsInitialPType2
1046
 
        exit;
1047
 
      end
1048
 
      else // must be gtpsInitialPType3
1049
 
      if (FExtraReq.Error = '')  and (ptprfPointer in FExtraReq.Result.Flags) then begin
1050
 
        // pointer
1051
 
        FKind := skPointer;
1052
 
        FTypeName := ClearAmpersand(PCLenToString(FWhatIsExprReq.Result.Name));
1053
 
        FInternalTypeName := FTypeName;
1054
 
        Result := True;
1055
 
        // ====> DONE
1056
 
        exit;
 
2862
        if not RequireRequests([gptrPTypeOfWhatis])
 
2863
        then exit;
 
2864
 
 
2865
        if (not IsReqError(gptrPTypeOfWhatis, False))
 
2866
        and (ptprfPointer in FReqResults[gptrPTypeOfWhatis].Result.Flags) then begin
 
2867
          // pointer
 
2868
          FKind := skPointer;
 
2869
          SetTypNameFromReq(gptrWhatisExpr);
 
2870
          Result := True;
 
2871
          // ====> DONE
 
2872
          exit;
 
2873
        end;
1057
2874
      end;
1058
2875
    end;
1059
2876
 
1060
 
    case FPTypeExprReq.Result.Kind of
 
2877
    case PTypeResult.Kind of
1061
2878
      ptprkError: begin
1062
2879
          // could be empty pointer @ArgProcedure
1063
2880
          Result := True; // nothing to be done, keep simple type, no name
1064
2881
        end;
1065
2882
      ptprkSimple: begin
1066
2883
          // may only need whatis, if current name isn't usable?
1067
 
          if FProcessState = gtpsInitialPType then begin
1068
 
            AddTypeReq(FWhatIsExprReq, 'whatis ' + FExpression);
1069
 
            FProcessState := gtpsInitialPType2;
1070
 
            // ====> state = gtpsInitialPType2
1071
 
          end
1072
 
          else begin
1073
 
            if (FWhatIsExprReq.Result.BaseName.Len > 0) then
1074
 
              FTypeName := PCLenToString(FWhatIsExprReq.Result.BaseName)
1075
 
            else
1076
 
              FTypeName := PCLenToString(FPTypeExprReq.Result.BaseName);
1077
 
            FInternalTypeName := FTypeName; // There may be an alias?
1078
 
            FKind := skSimple;
1079
 
            Result := True;
1080
 
            // ====> DONE
1081
 
          end;
 
2884
          if not RequireRequests([gptrWhatisExpr])
 
2885
          then exit;
 
2886
 
 
2887
          SetTypNameFromReq(gptrWhatisExpr, True);
 
2888
          FKind := skSimple;
 
2889
          Result := True;
 
2890
          // ====> DONE
1082
2891
        end;
1083
2892
      ptprkClass: begin
1084
 
          AddTypeReq(FWhatIsExprReq, 'whatis ' + FExpression);
1085
 
          FProcessState := gtpsClassWhatIs; // ====> state = ClassWhatis
 
2893
          Assert(False, 'GDBTypeInfo Class: Should be handled before');
 
2894
          ProcessClass;
1086
2895
        end;
1087
2896
      ptprkRecord: begin
1088
 
          FTypeName := PCLenToString(FPTypeExprReq.Result.BaseName);
1089
 
          FInternalTypeName := FTypeName; // There may be an alias?
 
2897
          SetTypNameFromReq(gptrWhatisExpr, True);
1090
2898
          DoRecord;
1091
2899
          Result := True;
1092
2900
          // ====> DONE
1093
2901
        end;
1094
2902
      ptprkEnum: begin
1095
 
          FTypeName := PCLenToString(FPTypeExprReq.Result.BaseName);
1096
 
          FInternalTypeName := FTypeName; //s There may be an alias?
 
2903
          SetTypNameFromReq(gptrWhatisExpr, True);
 
2904
          FTypeDeclaration := ClearAmpersand(PCLenToString(PTypeResult.Declaration));
1097
2905
          DoEnum;
1098
2906
          Result := True;
1099
2907
          // ====> DONE
1100
2908
        end;
1101
2909
      ptprkSet: begin
1102
 
          if FProcessState = gtpsInitialPType then begin
1103
 
            AddTypeReq(FWhatIsExprReq, 'whatis ' + FExpression);
1104
 
            FProcessState := gtpsInitialPType2;
1105
 
            // ====> state = gtpsInitialPType2
1106
 
          end
1107
 
          else begin
1108
 
            if (FWhatIsExprReq.Result.BaseName.Len > 0) then
1109
 
              FTypeName := PCLenToString(FWhatIsExprReq.Result.BaseName)
1110
 
            else
1111
 
              FTypeName := PCLenToString(FPTypeExprReq.Result.BaseName);
1112
 
            FInternalTypeName := FTypeName;
1113
 
            DoSet;
1114
 
            Result := True;
1115
 
            // ====> DONE
1116
 
          end;
 
2910
          if not RequireRequests([gptrWhatisExpr])
 
2911
          then exit;
 
2912
 
 
2913
          SetTypNameFromReq(gptrWhatisExpr, True);
 
2914
          // TODO: resolve enum-name (set of SomeEnum) if mode-full ?
 
2915
          FTypeDeclaration := ClearAmpersand(PCLenToString(PTypeResult.Declaration));
 
2916
          i := pos('set of  = ', FTypeDeclaration);
 
2917
          if  i > 0 then delete(FTypeDeclaration, i+7, 3);
 
2918
          DoSet;
 
2919
          Result := True;
 
2920
          // ====> DONE
1117
2921
        end;
1118
2922
      ptprkArray: begin
1119
 
          if FProcessState = gtpsInitialPType then begin
1120
 
            AddTypeReq(FWhatIsExprReq, 'whatis ' + FExpression);
1121
 
            FProcessState := gtpsInitialPType2;
1122
 
            // ====> state = gtpsInitialPType2
1123
 
          end
1124
 
          else begin
1125
 
            FKind := skSimple;
1126
 
            if (FWhatIsExprReq.Result.BaseName.Len > 0) then
1127
 
              FTypeName := PCLenToString(FWhatIsExprReq.Result.BaseName)
1128
 
            else
1129
 
              FTypeName := PCLenToString(FPTypeExprReq.Result.BaseName);
1130
 
            FInternalTypeName := FTypeName;
1131
 
            Result := True;
1132
 
            // ====> DONE
1133
 
          end;
 
2923
          Assert(False, 'GDBTypeInfo Array: Should be handled before');
 
2924
          ProcessArray;
1134
2925
        end;
1135
2926
      ptprkProcedure: begin
1136
2927
          // under stabs, procedure/function are always pointer // pointer to proc/func return empty type
1137
 
          if FClassIsPointer // Dwarf
1138
 
          and (ptprfPointer in FPTypeExprReq.Result.Flags)
 
2928
          if (gtcfClassIsPointer in FCreationFlags) // Dwarf
 
2929
          and (ptprfPointer in PTypeResult.Flags)
1139
2930
          then begin
1140
 
            AddTypeReq(FWhatIsExprReq, 'whatis ' + FExpression);
1141
 
            FProcessState := gtpsSimplePointer;
1142
 
            // ====> state = SimplePointer
1143
 
          end
1144
 
          else
1145
 
          if FProcessState = gtpsInitialPType then begin
1146
 
            AddTypeReq(FWhatIsExprReq, 'whatis ' + FExpression);
1147
 
            FProcessState := gtpsInitialPType2;
1148
 
            // ====> state = gtpsInitialPType2
1149
 
          end
1150
 
          else begin
1151
 
            if (FWhatIsExprReq.Result.BaseName.Len > 0) then
1152
 
              FTypeName := PCLenToString(FWhatIsExprReq.Result.BaseName)
1153
 
            else
1154
 
              FTypeName := PCLenToString(FPTypeExprReq.Result.BaseName);
1155
 
            if FTypeName = '' then FTypeName := 'procedure';
1156
 
            FInternalTypeName := FTypeName;
1157
 
            DoProcedure;
1158
 
            Result := True;
1159
 
            // ====> DONE
 
2931
            ProcessSimplePointer;
 
2932
            exit;
1160
2933
          end;
 
2934
 
 
2935
          if not RequireRequests([gptrWhatisExpr])
 
2936
          then exit;
 
2937
 
 
2938
          SetTypNameFromReq(gptrWhatisExpr, True, 'procedure');
 
2939
          DoProcedure;
 
2940
          Result := True;
 
2941
          // ====> DONE
1161
2942
        end;
1162
2943
      ptprkFunction: begin
1163
2944
          // under stabs, procedure/function are always pointer // pointer to proc/func return empty type
1164
 
          if FClassIsPointer // Dwarf
1165
 
          and (ptprfPointer in FPTypeExprReq.Result.Flags)
 
2945
          if (gtcfClassIsPointer in FCreationFlags) // Dwarf
 
2946
          and (ptprfPointer in PTypeResult.Flags)
1166
2947
          then begin
1167
 
            AddTypeReq(FWhatIsExprReq, 'whatis ' + FExpression);
1168
 
            FProcessState := gtpsSimplePointer;
1169
 
            // ====> state = SimplePointer
1170
 
          end
1171
 
          else
1172
 
          if FProcessState = gtpsInitialPType then begin
1173
 
            AddTypeReq(FWhatIsExprReq, 'whatis ' + FExpression);
1174
 
            FProcessState := gtpsInitialPType2;
1175
 
            // ====> state = gtpsInitialPType2
1176
 
          end
1177
 
          else begin
1178
 
            if (FWhatIsExprReq.Result.BaseName.Len > 0) then
1179
 
              FTypeName := PCLenToString(FWhatIsExprReq.Result.BaseName)
1180
 
            else
1181
 
              FTypeName := PCLenToString(FPTypeExprReq.Result.BaseName);
1182
 
            if FTypeName = '' then FTypeName := 'function';
1183
 
            FInternalTypeName := FTypeName;
1184
 
            DoFunction;
1185
 
            Result := True;
1186
 
            // ====> DONE
1187
 
        end;
1188
 
      end;
1189
 
    end;
1190
 
  end;
1191
 
 
1192
 
  procedure InitializeProcessing;
1193
 
  begin
1194
 
    AddTypeReq(FPTypeExprReq, 'ptype ' + FExpression);
1195
 
    FProcessState := gtpsInitialPType;
 
2948
            ProcessSimplePointer;
 
2949
            exit;
 
2950
          end;
 
2951
 
 
2952
          if not RequireRequests([gptrWhatisExpr])
 
2953
          then exit;
 
2954
 
 
2955
          SetTypNameFromReq(gptrWhatisExpr, True, 'function');
 
2956
          DoFunction;
 
2957
          Result := True;
 
2958
          // ====> DONE
 
2959
      end;
 
2960
    end;
 
2961
  end;
 
2962
 
 
2963
  procedure ProcessInitial;
 
2964
  begin
 
2965
    FProcessState := gtpsInitial;
 
2966
    if FExpression = '' then begin;
 
2967
      ProcessInitialSimple;
 
2968
      exit;
 
2969
    end;
 
2970
 
 
2971
    if FParsedExpression = nil
 
2972
    then FParsedExpression := TGDBExpression.Create(FExpression);
 
2973
    // Does not set FLastEvalRequest
 
2974
    if FParsedExpression.NeedValidation(FEvalRequest)
 
2975
    then exit;
 
2976
 
 
2977
    FExpression := FParsedExpression.Text;
 
2978
 
 
2979
    ProcessInitialSimple;
 
2980
  end;
 
2981
 
 
2982
  procedure MergeSubProcessRequests;
 
2983
  var
 
2984
    SubType: TGDBType;
 
2985
  begin
 
2986
    SubType := FFirstProcessingSubType;
 
2987
    while SubType <> nil do begin
 
2988
      if (FEvalRequest =  nil)
 
2989
      then FEvalRequest := SubType.FEvalRequest
 
2990
      else if FLastEvalRequest <> nil
 
2991
      then FLastEvalRequest^.Next := SubType.FEvalRequest
 
2992
      else begin
 
2993
        // Find last req
 
2994
        FLastEvalRequest := FEvalRequest;
 
2995
        while (FLastEvalRequest^.Next <> nil) do
 
2996
          FLastEvalRequest := FLastEvalRequest^.Next;
 
2997
        FLastEvalRequest^.Next := SubType.FEvalRequest;
 
2998
      end;
 
2999
      FLastEvalRequest := SubType.FLastEvalRequest;
 
3000
      SubType := SubType.FNextProcessingSubType;
 
3001
    end;
 
3002
  end;
 
3003
 
 
3004
  function ProcessSubProcessRequests: Boolean;
 
3005
  var
 
3006
    SubType, PrevSubType: TGDBType;
 
3007
  begin
 
3008
    PrevSubType := nil;
 
3009
    SubType := FFirstProcessingSubType;
 
3010
    while SubType <> nil do begin
 
3011
      DebugLnEnter(DBGMI_TYPE_INFO, ['>>Enter Sub-Request']);
 
3012
      if SubType.ProcessExpression then begin
 
3013
        if PrevSubType = nil
 
3014
        then FFirstProcessingSubType := SubType.FNextProcessingSubType
 
3015
        else PrevSubType.FNextProcessingSubType := SubType.FNextProcessingSubType;
 
3016
      end
 
3017
      else
 
3018
        PrevSubType := SubType;
 
3019
      SubType := SubType.FNextProcessingSubType;
 
3020
      DebugLnExit(DBGMI_TYPE_INFO, ['>>Leave Sub-Request']);
 
3021
    end;
 
3022
 
 
3023
    Result := FFirstProcessingSubType = nil;
1196
3024
  end;
1197
3025
 
1198
3026
var
1199
3027
  OldProcessState: TGDBTypeProcessState;
 
3028
  OldReqMade: TGDBTypeProcessRequests;
 
3029
  s: string;
1200
3030
begin
1201
3031
  Result := False;
1202
3032
  FEvalRequest := nil;
 
3033
  FLastEvalRequest := nil;
1203
3034
  Lines := nil;
 
3035
  WriteStr(s, FProcessState); // TODO dbgs
 
3036
  DebugLnEnter(DBGMI_TYPE_INFO, ['>>Enter: TGDBType.ProcessExpression: state = ', s, '   Expression="', FExpression, '"']);
 
3037
  try
 
3038
 
 
3039
 
 
3040
  if FFirstProcessingSubType <> nil then begin
 
3041
    if not ProcessSubProcessRequests then begin
 
3042
      MergeSubProcessRequests;
 
3043
      exit;
 
3044
    end;
 
3045
  end;
 
3046
 
1204
3047
  OldProcessState := FProcessState;
 
3048
  OldReqMade := FProccesReuestsMade;
1205
3049
 
1206
3050
  case FProcessState of
1207
 
    gtpsInitial:         InitializeProcessing;
1208
 
    gtpsInitialPType,
1209
 
    gtpsInitialPType2,
1210
 
    gtpsInitialPType3:   ProcessInitialPType;
1211
 
    gtpsSimplePointer:   ProcessSimplePointer;
1212
 
    gtpsClassWhatIs:     ProcessClassWhatIs;
1213
 
    gtpsClassNameWhatIs: ProcessClassNameWhatIs;
1214
 
    gtpsClassNamePType:  ProcessClassNamePType;
 
3051
    gtpsInitial:            ProcessInitial;
 
3052
    gtpsInitialSimple:      ProcessInitialSimple;
 
3053
    gtpsSimplePointer:      ProcessSimplePointer;
 
3054
    gtpsClass:              ProcessClass;
 
3055
    gtpsClassAutoCast:      ProcessClassAutoCast;
 
3056
    gtpsClassPointer:       ProcessClassPointer;
 
3057
    gtpsFinishProcessClass: FinishProcessClass;
 
3058
    gtpsClassAncestor:      ProcessClassAncestor;
 
3059
    gtpsArray:              ProcessArray;
 
3060
    gtpsEvalExpr:           EvaluateExpression;
 
3061
    gtpsEvalExprArray:      EvaluateExpressionArray;
 
3062
    gtpsEvalExprDynArray:   EvaluateExpressionDynArray;
 
3063
    gtpsEvalExprDynArrayGetData: EvaluateExpressionDynArrayGetData;
1215
3064
  end;
1216
3065
 
1217
3066
  FreeAndNil(Lines);
1218
 
  if (FProcessState = OldProcessState) and (not Result) and (FEvalRequest = nil)
 
3067
  if Result and not(FEvalStarted)
 
3068
  then begin
 
3069
    Result := False;
 
3070
    FEvalStarted := True;
 
3071
    EvaluateExpression;
 
3072
  end;
 
3073
 
 
3074
  if Result
 
3075
  then FProcessState := gtpsFinished;
 
3076
 
 
3077
  if FFirstProcessingSubType <> nil then
 
3078
    MergeSubProcessRequests
 
3079
  else
 
3080
  if (FProcessState = OldProcessState) and (FProccesReuestsMade = OldReqMade)
 
3081
  and (not Result) and (FEvalRequest = nil)
1219
3082
  then begin
1220
3083
    debugln('ERROR: detected state loop in ProcessExpression');
1221
3084
    Result := True;
1222
3085
  end;
 
3086
  finally
 
3087
    WriteStr(s, FProcessState);
 
3088
    DebugLnExit(DBGMI_TYPE_INFO, ['<<Exit:  TGDBType.ProcessExpression: state = ', s, '  Result=', dbgs(Result),
 
3089
                 ' Kind=', dbgs(Kind), ' Attr=', dbgs(Attributes), ' Typename="', TypeName, '" InternTpName="', FInternalTypeName,'" TypeDeclaration="', TypeDeclaration, '"']);
 
3090
  end;
1223
3091
end;
1224
3092
 
1225
3093
{ TGDBPTypes }
1237
3105
  end;
1238
3106
end;
1239
3107
 
 
3108
initialization
 
3109
  DBGMI_TYPE_INFO := DebugLogger.RegisterLogGroup('DBGMI_TYPE_INFO' {$IFDEF DBGMI_TYPE_INFO} , True {$ENDIF} );
 
3110
 
1240
3111
end.