/debugger/gdbtypeinfo.pp

http://github.com/graemeg/lazarus · Puppet · 627 lines · 545 code · 82 blank · 0 comment · 90 complexity · 7196e365af0c47d45d208750db5996c4 MD5 · raw file

  1. { $Id$ }
  2. { ----------------------------------------------
  3. GDBTypeInfo.pp - Debugger helper class
  4. ----------------------------------------------
  5. @created(Wed Mar 29th WET 2003)
  6. @lastmod($Date$)
  7. @author(Marc Weustink <marc@@dommelstein.net>)
  8. This unit contains a helper class for decoding PType output.
  9. ***************************************************************************
  10. * *
  11. * This source is free software; you can redistribute it and/or modify *
  12. * it under the terms of the GNU General Public License as published by *
  13. * the Free Software Foundation; either version 2 of the License, or *
  14. * (at your option) any later version. *
  15. * *
  16. * This code is distributed in the hope that it will be useful, but *
  17. * WITHOUT ANY WARRANTY; without even the implied warranty of *
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
  19. * General Public License for more details. *
  20. * *
  21. * A copy of the GNU General Public License is available on the World *
  22. * Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also *
  23. * obtain it by writing to the Free Software Foundation, *
  24. * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
  25. * *
  26. ***************************************************************************
  27. }
  28. unit GDBTypeInfo;
  29. {$mode objfpc}{$H+}
  30. interface
  31. uses
  32. Classes, SysUtils;
  33. (*
  34. ptype = {
  35. family = "class" | "record" | "enum" | "set" | "procedure" | "function" | "simple" | "pointer"
  36. [ ancestor = "...", ]
  37. [ private = "[" ( "{" name = "...", type = ptype "}" )* "}," ]
  38. [ protected = "[" ( "{" name = "...", type = ptype "}" )* "}," ]
  39. [ public = "[" ( "{" name = "...", type = ptype "}" )* "},"]
  40. [ published = "[" ( "{" name = "...", type = ptype "}" )* "}," ]
  41. [ members = "[" ( "..." )* "]," | "[" ( "{" name = "...", type = "..." "}" )* "]," ]
  42. [ args = "[" ( "..." )* "]," ]
  43. [ result = "..." ]
  44. [ name = "..." ]
  45. [ type = "..." ]
  46. *)
  47. type
  48. TGDBSymbolKind = (skClass, skRecord, skEnum, skSet, skProcedure, skFunction, skSimple, skPointer);
  49. TGDBFieldLocation = (flPrivate, flProtected, flPublic, flPublished);
  50. TGDBFieldFlag = (ffVirtual);
  51. TGDBFieldFlags = set of TGDBFieldFlag;
  52. TGDBType = class;
  53. TGDBField = class(TObject)
  54. private
  55. FName: String;
  56. FFlags: TGDBFieldFlags;
  57. FLocation: TGDBFieldLocation;
  58. FGDBType: TGDBType;
  59. protected
  60. public
  61. constructor Create;
  62. destructor Destroy; override;
  63. property Name: String read FName;
  64. property GDBType: TGDBType read FGDBType;
  65. property Location: TGDBFieldLocation read FLocation;
  66. property Flags: TGDBFieldFlags read FFlags;
  67. end;
  68. TGDBFields = class(TObject)
  69. private
  70. FList: TList;
  71. function GetField(const AIndex: Integer): TGDBField;
  72. function GetCount: Integer;
  73. protected
  74. public
  75. constructor Create;
  76. destructor Destroy; override;
  77. property Count: Integer read GetCount;
  78. property Items[const AIndex: Integer]: TGDBField read GetField; default;
  79. end;
  80. TGDBTypes = class(TObject)
  81. private
  82. FList: TList;
  83. function GetType(const AIndex: Integer): TGDBType;
  84. function GetCount: Integer;
  85. protected
  86. public
  87. constructor Create;
  88. constructor CreateFromCSV(AValues: String);
  89. destructor Destroy; override;
  90. property Count: Integer read GetCount;
  91. property Items[const AIndex: Integer]: TGDBType read GetType; default;
  92. end;
  93. { TGDBType }
  94. TGDBType = class(TObject)
  95. private
  96. FAncestor: String;
  97. FResult: TGDBType;
  98. FArguments: TGDBTypes;
  99. FFields: TGDBFields;
  100. FKind: TGDBSymbolKind;
  101. FMembers: TStrings;
  102. FTypeName: String;
  103. protected
  104. public
  105. constructor Create;
  106. constructor CreateFromValues(const AValues: String);
  107. destructor Destroy; override;
  108. property Ancestor: String read FAncestor;
  109. property Arguments: TGDBTypes read FArguments;
  110. property Fields: TGDBFields read FFields;
  111. property Kind: TGDBSymbolKind read FKind;
  112. property TypeName: String read FTypeName;
  113. property Members: TStrings read FMembers;
  114. property Result: TGDBType read FResult;
  115. end;
  116. function CreatePTypeValueList(AResultValues: String): TStringList;
  117. implementation
  118. function GetPart(const ASkipTo, AnEnd: array of String; var ASource: String): String;
  119. var
  120. n, i, idx, SkipLen: Integer;
  121. begin
  122. idx := 0;
  123. SkipLen := 0;
  124. if High(ASkipTo) <> -1
  125. then begin
  126. for n := Low(ASkipTo) to High(ASkipTo) do
  127. begin
  128. if ASkipTo[n] <> ''
  129. then begin
  130. i := Pos(ASkipTo[n], ASource);
  131. if (i > 0) and ((idx = 0) or (i < idx))
  132. then begin
  133. idx := i;
  134. SkipLen := Length(ASkipTo[n]);
  135. end;
  136. end;
  137. end;
  138. if idx = 0
  139. then begin
  140. Result := '';
  141. Exit;
  142. end;
  143. Delete(ASource, 1, idx + SkipLen - 1);
  144. end;
  145. idx := 0;
  146. for n := Low(AnEnd) to High(AnEnd) do
  147. begin
  148. if AnEnd[n] <> ''
  149. then begin
  150. i := Pos(AnEnd[n], ASource);
  151. if (i > 0) and ((idx = 0) or (i < idx))
  152. then idx := i;
  153. end;
  154. end;
  155. if idx = 0
  156. then begin
  157. Result := ASource;
  158. ASource := '';
  159. end
  160. else begin
  161. Result := Copy(ASource, 1, idx - 1);
  162. Delete(ASource, 1, idx - 1);
  163. end;
  164. end;
  165. function CreatePTypeValueList(AResultValues: String): TStringList;
  166. var
  167. S, Line: String;
  168. Lines: TStringList;
  169. procedure DoRecord;
  170. var
  171. n: Integer;
  172. S, Members: String;
  173. begin
  174. Result.Add('family=record');
  175. Members := '';
  176. //concatinate all lines and skip last end
  177. S := '';
  178. for n := 0 to Lines.Count - 2 do
  179. S := S + Lines[n];
  180. while S <> '' do
  181. begin
  182. if Members <> '' then Members := Members + ',';
  183. Members := Members + '{name=' + GetPart([' '], [' '], S);
  184. Members := Members + ',type=' + GetPart([' : '], [';'], S) + '}';
  185. end;
  186. Result.Add('members=[' + Members + ']');
  187. end;
  188. procedure DoEnum;
  189. var
  190. n: Integer;
  191. S: String;
  192. begin
  193. Result.Add('family=enum');
  194. S := GetPart(['('], [], Line);
  195. //concatinate all lines
  196. for n := 0 to Lines.Count - 1 do
  197. S := S + Lines[n];
  198. S := GetPart([], [')'], S);
  199. Result.Add('members=[' + StringReplace(S, ' ', '', [rfReplaceAll]) + ']');
  200. end;
  201. procedure DoProcedure;
  202. var
  203. n: Integer;
  204. S: String;
  205. begin
  206. Result.Add('family=procedure');
  207. S := GetPart(['('], [''], Line);
  208. //concatinate all lines
  209. for n := 0 to Lines.Count - 1 do
  210. S := S + Lines[n];
  211. S := GetPart([''], [')'], S);
  212. Result.Add('args=[' + StringReplace(S, ', ', ',', [rfReplaceAll]) + ']');
  213. end;
  214. procedure DoFunction;
  215. var
  216. n: Integer;
  217. S, Args: String;
  218. begin
  219. Result.Add('family=function');
  220. S := GetPart(['('], [], Line);
  221. //concatinate all lines
  222. for n := 0 to Lines.Count - 1 do
  223. S := S + Lines[n];
  224. Args := GetPart([], [')'], S);
  225. S := GetPart([' : '], [], S);
  226. Result.Add('args=[' + StringReplace(Args, ', ', ',', [rfReplaceAll]) + ']');
  227. Result.Add('result=' + S);
  228. end;
  229. procedure DoClass;
  230. begin
  231. Result.Add('family=class');
  232. Result.Add('ancestor=' + GetPart([': public '], [' '], Line));
  233. end;
  234. begin
  235. Result := TStringList.Create;
  236. if AResultValues = '' then Exit;
  237. Lines := TStringList.Create;
  238. try
  239. Lines.Text := AResultValues;
  240. if Lines.Count = 0 then Exit;
  241. Line := Lines[0];
  242. Lines.Delete(0);
  243. S := GetPart(['type = '], [' '], Line);
  244. if S = '' then Exit;
  245. if Pos(' = class ', Line) > 0
  246. then DoClass
  247. else if S[1] = '^'
  248. then begin
  249. Result.Add('family=pointer');
  250. Result.Add('type=' + GetPart(['^'], [' ='], S));
  251. end
  252. else if S = 'set'
  253. then begin
  254. Result.Add('family=set');
  255. Result.Add('type=' + Copy(Line, 5, Length(Line)));
  256. end
  257. else if S = 'procedure'
  258. then DoProcedure
  259. else if S = 'function'
  260. then DoFunction
  261. else if Pos(' = (', Line) > 0
  262. then DoEnum
  263. else if Pos(' = record', Line) > 0
  264. then DoRecord
  265. else begin
  266. Result.Add('family=simple');
  267. Result.Add('type=' + S);
  268. end;
  269. finally
  270. Lines.Free;
  271. end;
  272. end;
  273. { TGDBField }
  274. constructor TGDBField.Create;
  275. begin
  276. FFlags := [];
  277. FGDBType := nil;
  278. FLocation := flPublic;
  279. end;
  280. destructor TGDBField.Destroy;
  281. begin
  282. if FGDBType<>nil then FreeAndNil(FGDBType);
  283. inherited Destroy;
  284. end;
  285. { TGDBFields }
  286. constructor TGDBFields.Create;
  287. begin
  288. FList := TList.Create;
  289. inherited;
  290. end;
  291. destructor TGDBFields.Destroy;
  292. var
  293. n: Integer;
  294. begin
  295. for n := 0 to Count - 1 do
  296. Items[n].Free;
  297. FreeAndNil(FList);
  298. inherited;
  299. end;
  300. function TGDBFields.GetCount: Integer;
  301. begin
  302. Result := FList.Count;
  303. end;
  304. function TGDBFields.GetField(const AIndex: Integer): TGDBField;
  305. begin
  306. Result := TGDBField(FList[AIndex]);
  307. end;
  308. { TGDBPType }
  309. constructor TGDBType.Create;
  310. begin
  311. FResult := nil;
  312. FArguments := nil;
  313. FFields := nil;
  314. FMembers := nil;
  315. inherited Create;
  316. end;
  317. constructor TGDBType.CreateFromValues(const AValues: String);
  318. var
  319. S, Line: String;
  320. Lines: TStringList;
  321. procedure DoRecord;
  322. var
  323. n: Integer;
  324. S: String;
  325. Field: TGDBField;
  326. begin
  327. FKind := skRecord;
  328. FFields := TGDBFields.Create;
  329. //concatenate all lines and skip last end
  330. S := '';
  331. for n := 0 to Lines.Count - 2 do
  332. S := S + Lines[n];
  333. while S <> '' do
  334. begin
  335. Field := TGDBField.Create;
  336. Field.FName := GetPart([' '], [' '], S);
  337. Field.FLocation := flPublic;
  338. Field.FGDBType := TGDBType.Create;
  339. Field.FGDBType.FKind := skSimple; // for now
  340. Field.FGDBType.FTypeName := GetPart([' : '], [';'], S);
  341. FFields.FList.Add(Field);
  342. Delete(S, 1, 1);
  343. end;
  344. end;
  345. procedure DoEnum;
  346. var
  347. n: Integer;
  348. S: String;
  349. begin
  350. FKind := skEnum;
  351. S := GetPart(['('], [], Line);
  352. //concatenate all lines
  353. for n := 0 to Lines.Count - 1 do
  354. S := S + Lines[n];
  355. S := GetPart([], [')'], S);
  356. FMembers := TStringList.Create;
  357. FMembers.Text := StringReplace(S, ' ', #13#10, [rfReplaceAll]);
  358. end;
  359. procedure DoSet;
  360. var
  361. n: Integer;
  362. S: String;
  363. begin
  364. FKind := skSet;
  365. S := Copy(Line, 5, Length(Line));
  366. for n := 0 to Lines.Count - 1 do
  367. S := S + Lines[n];
  368. if Pos('=', S) = 0
  369. then FTypeName := S
  370. else begin
  371. S := GetPart(['('], [')'], S);
  372. FMembers := TStringList.Create;
  373. FMembers.Text := StringReplace(StringReplace(S, ',', #13#10, [rfReplaceAll]), ' ', '', [rfReplaceAll]);
  374. end;
  375. end;
  376. procedure DoProcedure;
  377. var
  378. n: Integer;
  379. S: String;
  380. begin
  381. FKind := skProcedure;
  382. S := GetPart(['('], [], Line);
  383. //concatenate all lines
  384. for n := 0 to Lines.Count - 1 do
  385. S := S + Lines[n];
  386. S := GetPart([], [')'], S);
  387. FArguments := TGDBTypes.CreateFromCSV(S);
  388. end;
  389. procedure DoFunction;
  390. var
  391. n: Integer;
  392. S: String;
  393. begin
  394. FKind := skFunction;
  395. S := GetPart(['('], [], Line);
  396. //concatenate all lines
  397. for n := 0 to Lines.Count - 1 do
  398. S := S + Lines[n];
  399. FArguments := TGDBTypes.CreateFromCSV(GetPart([], [')'], S));
  400. FResult := TGDBType.Create;
  401. FResult.FKind := skSimple; // for now
  402. FResult.FTypeName := GetPart([' : '], [], S);
  403. end;
  404. procedure DoClass;
  405. var
  406. n: Integer;
  407. Field: TGDBField;
  408. S: String;
  409. Location: TGDBFieldLocation;
  410. begin
  411. FKind := skClass;
  412. FAncestor := GetPart([': public '], [' '], Line);
  413. FFields := TGDBFields.Create;
  414. Location := flPublished;
  415. for n := 0 to Lines.Count - 2 do
  416. begin
  417. S := Lines[n];
  418. if S = '' then Continue;
  419. if S = ' private' then Location := flPrivate
  420. else if S = ' protected' then Location := flProtected
  421. else if S = ' public' then Location := flPublic
  422. else if S = ' published' then Location := flPublished
  423. else begin
  424. Field := TGDBField.Create;
  425. Field.FLocation := Location;
  426. Field.FGDBType := TGDBType.Create;
  427. FFields.FList.Add(Field);
  428. if Pos(' procedure ', S) > 0
  429. then begin
  430. Field.FName := GetPart(['procedure '], [' ', ';'], S);
  431. Field.FGDBType.FKind := skProcedure;
  432. Field.FGDBType.FArguments := TGDBTypes.CreateFromCSV(GetPart(['('], [')'], S));
  433. if GetPart(['; '], [';'], S) = 'virtual'
  434. then Field.FFlags := [ffVirtual];
  435. end
  436. else if Pos(' function ', S) > 0
  437. then begin
  438. Field.FName := GetPart(['function '], [' ', ';'], S);
  439. Field.FGDBType.FKind := skFunction;
  440. Field.FGDBType.FArguments := TGDBTypes.CreateFromCSV(GetPart(['('], [')'], S));
  441. Field.FGDBType.FResult := TGDBType.Create;
  442. Field.FGDBType.FResult.FKind := skSimple; // for now
  443. Field.FGDBType.FResult.FTypeName := GetPart([' : '], [';'], S);
  444. if GetPart(['; '], [';'], S) = 'virtual'
  445. then Field.FFlags := [ffVirtual];
  446. end
  447. else begin
  448. Field.FName := GetPart([' '], [' '], S);
  449. Field.FGDBType.FKind := skSimple; // for now
  450. Field.FGDBType.FTypeName := GetPart([' : '], [';'], S);
  451. end;
  452. end;
  453. end;
  454. end;
  455. var
  456. HasClass: Boolean;
  457. begin
  458. Create;
  459. if AValues = '' then Exit;
  460. Lines := TStringList.Create;
  461. try
  462. Lines.Text := AValues;
  463. if Lines.Count = 0 then Exit;
  464. Line := Lines[0];
  465. Lines.Delete(0);
  466. S := GetPart(['type = '], [' '], Line);
  467. if S = '' then Exit;
  468. HasClass := Pos(' = class ', Line) > 0;
  469. if HasClass
  470. and (S[2] <> '^') // pointer to class is handled next
  471. then begin
  472. FTypeName := GetPart(['^'], [' '], S);
  473. DoClass;
  474. end
  475. else if S[1] = '^'
  476. then begin
  477. FKind := skPointer;
  478. if HasClass
  479. then FTypeName := GetPart(['^^'], [' ='], S)
  480. else FTypeName := GetPart(['^'], [' ='], S);
  481. end
  482. else if S = 'set'
  483. then DoSet
  484. else if S = 'procedure'
  485. then DoProcedure
  486. else if S = 'function'
  487. then DoFunction
  488. else if Pos(' = (', Line) > 0
  489. then DoEnum
  490. else if Pos(' = record', Line) > 0
  491. then DoRecord
  492. else begin
  493. FKind := skSimple;
  494. FTypeName := S;
  495. end;
  496. finally
  497. Lines.Free;
  498. end;
  499. end;
  500. destructor TGDBType.Destroy;
  501. begin
  502. if FResult<>nil then FreeAndNil(FResult);
  503. if FArguments<>nil then FreeAndNil(FArguments);
  504. if FFields<>nil then FreeAndNil(FFields);
  505. if FMembers<>nil then FreeAndNil(FMembers);
  506. inherited;
  507. end;
  508. { TGDBPTypes }
  509. constructor TGDBTypes.Create;
  510. begin
  511. FList := TList.Create;
  512. inherited;
  513. end;
  514. constructor TGDBTypes.CreateFromCSV(AValues: String);
  515. var
  516. GDBType: TGDBType;
  517. begin
  518. Create;
  519. while AValues <> '' do
  520. begin
  521. GDBType := TGDBType.Create;
  522. GDBType.FKind := skSimple;
  523. GDBType.FTypeName := GetPart([], [', '], AValues);
  524. FList.Add(GDBType);
  525. {if Length(AValues) >= 2 then} Delete(AValues, 1, 2);
  526. end;
  527. end;
  528. destructor TGDBTypes.Destroy;
  529. var
  530. n: Integer;
  531. begin
  532. for n := 0 to Count - 1 do
  533. Items[n].Free;
  534. FreeAndNil(FList);
  535. inherited;
  536. end;
  537. function TGDBTypes.GetCount: Integer;
  538. begin
  539. Result := Flist.Count;
  540. end;
  541. function TGDBTypes.GetType(const AIndex: Integer): TGDBType;
  542. begin
  543. Result := TGDBType(FList[AIndex]);
  544. end;
  545. end.