Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

852 строки
28 KiB

  1. unit HeaderGenerator;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. Classes, SysUtils, DOM, fgl, variants;
  6. type
  7. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  8. THeaderGenerator = class(TObject)
  9. private type
  10. TvkObjectType = (
  11. otUnknown,
  12. otType,
  13. otHandle,
  14. otFuncPtr,
  15. otStruct,
  16. otEnum,
  17. otCommand);
  18. TvkObjectTypes = set of TvkObjectType;
  19. TvkObject = class;
  20. TvkObjectList = class(specialize TFPGObjectList<TvkObject>)
  21. public
  22. function FindObj(const aName: DOMstring; const aTypes: TvkObjectTypes; out aObject): Boolean;
  23. procedure MarkObj(const aName: DOMstring; const aTypes: TvkObjectTypes; const aMark: Integer);
  24. end;
  25. ////////////////////////////////////////////////////////////////////////////////////////////
  26. TvkObject = class(TObject)
  27. private
  28. fType: TvkObjectType;
  29. fMark: Integer;
  30. fName: DOMString;
  31. fComment: DOMString;
  32. fList: TvkObjectList;
  33. private
  34. procedure SetMark(aValue: Integer);
  35. protected
  36. procedure DoMark(const aMark: Integer); virtual;
  37. public
  38. property Mark: Integer read fMark write SetMark;
  39. property Name: DOMString read fName write fName;
  40. property Comment: DOMString read fComment write fComment;
  41. property VkType: TvkObjectType read fType;
  42. property List: TvkObjectList read fList write fList;
  43. procedure AddCommentFromXml(xml: TDOMNode);
  44. constructor Create(const aType: TvkObjectType);
  45. public
  46. class function CreateFromXml(const xml: TDOMNode): THeaderGenerator.TvkObject;
  47. end;
  48. ////////////////////////////////////////////////////////////////////////////////////////////
  49. TvkTypeSimple = class(TvkObject)
  50. private
  51. fParent: DOMString;
  52. protected
  53. procedure DoMark(const aMark: Integer); override;
  54. public
  55. property Parent: DOMString read fParent write fParent;
  56. public
  57. class function CreateFromXml(const xml: TDOMNode): THeaderGenerator.TvkTypeSimple;
  58. end;
  59. ////////////////////////////////////////////////////////////////////////////////////////////
  60. TvkTypeHandle = class(TvkTypeSimple)
  61. private
  62. fNonDispatchable: Boolean;
  63. public
  64. property NonDispatchable: Boolean read fNonDispatchable write fNonDispatchable;
  65. public
  66. class function CreateFromXml(const xml: TDOMNode): THeaderGenerator.TvkTypeHandle;
  67. end;
  68. ////////////////////////////////////////////////////////////////////////////////////////////
  69. TvkTypeFunction = class(TvkObject)
  70. private type
  71. TArgument = class(TObject)
  72. Typ: DOMString;
  73. Name: DOMString;
  74. IsPointer: Boolean;
  75. IsConst: Boolean;
  76. end;
  77. TArgumentList = specialize TFPGObjectList<TArgument>;
  78. private
  79. fReturnValue: TArgument;
  80. fArguments: TArgumentList;
  81. protected
  82. procedure DoMark(const aMark: Integer); override;
  83. public
  84. property ReturnValue: TArgument read fReturnValue;
  85. property Arguments: TArgumentList read fArguments;
  86. constructor Create(const aType: TvkObjectType);
  87. destructor Destroy; override;
  88. end;
  89. ////////////////////////////////////////////////////////////////////////////////////////////
  90. TvkTypeFunctionPtr = class(TvkTypeFunction)
  91. public
  92. class function CreateFromXml(const xml: TDOMNode): THeaderGenerator.TvkTypeFunctionPtr;
  93. end;
  94. ////////////////////////////////////////////////////////////////////////////////////////////
  95. TvkCommand = class(TvkTypeFunction)
  96. public
  97. class function CreateFromXml(const xml: TDOMNode): THeaderGenerator.TvkCommand;
  98. end;
  99. ////////////////////////////////////////////////////////////////////////////////////////////
  100. TvkTypeStruct = class(TvkObject)
  101. private type
  102. TMember = class(TObject)
  103. Typ: DOMString;
  104. Name: DOMString;
  105. ArrSize: Integer;
  106. IsPointer: Boolean;
  107. IsConst: Boolean;
  108. end;
  109. TMemberList = specialize TFPGObjectList<TMember>;
  110. private
  111. fIsUnion: Boolean;
  112. fMember: TMemberList;
  113. protected
  114. procedure DoMark(const aMark: Integer); override;
  115. public
  116. property Member: TMemberList read fMember;
  117. property IsUnion: Boolean read fIsUnion write fIsUnion;
  118. constructor Create(const aType: TvkObjectType);
  119. destructor Destroy; override;
  120. public
  121. class function CreateFromXml(const xml: TDOMNode): THeaderGenerator.TvkTypeStruct;
  122. end;
  123. ////////////////////////////////////////////////////////////////////////////////////////////
  124. TvkTypeEnum = class(TvkObject)
  125. private type
  126. TValue = class(TObject)
  127. Name: DOMString;
  128. Value: Variant;
  129. IsBit: Boolean;
  130. end;
  131. TValueList = specialize TFPGObjectList<TValue>;
  132. private
  133. fValues: TValueList;
  134. public
  135. property Values: TValueList read fValues;
  136. constructor Create(const aType: TvkObjectType);
  137. destructor Destroy; override;
  138. public
  139. class function CreateFromXml(const xml: TDOMNode): THeaderGenerator.TvkTypeEnum;
  140. end;
  141. private const
  142. VK_OBJECT_TYPES: TvkObjectTypes = [ otType, otHandle, otFuncPtr, otStruct, otEnum ];
  143. private
  144. fDocument: TXMLDocument;
  145. fComment: DOMString;
  146. fObjects: TvkObjectList;
  147. public
  148. procedure ReadFile(const aFilename: String);
  149. procedure ReadFile(const aStream: TStream);
  150. procedure Clear;
  151. constructor Create;
  152. destructor Destroy; override;
  153. end;
  154. implementation
  155. uses
  156. XMLRead, RegExpr;
  157. type
  158. XmlException = class(Exception)
  159. public
  160. xml: TDOMNode;
  161. constructor Create(const aMsg: WideString; const aXml: TDOMNode);
  162. end;
  163. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  164. function FormatType(const aType: THeaderGenerator.TvkObjectType): WideString;
  165. begin
  166. case aType of
  167. otType: result := 'TYPE';
  168. otHandle: result := 'HANDLE';
  169. otFuncPtr: result := 'FUNCPTR';
  170. otStruct: result := 'STRUCT';
  171. otEnum: result := 'ENUM';
  172. otCommand: result := 'COMMAND';
  173. else
  174. result := '';
  175. end;
  176. end;
  177. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  178. procedure WriteResolveWarning(const aName: DOMString);
  179. begin
  180. WriteLn('WARNING! unable to resolve identifier: ' + aName);
  181. end;
  182. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  183. function GetNodeValue(xml: TDOMNode; const aName: WideString): DOMString;
  184. var x: TDOMNode;
  185. begin
  186. x := xml.FindNode(aName);
  187. if not Assigned(x) then
  188. raise XmlException.Create(xml.NodeName + ' witout child ''' + aName + '''', xml);
  189. result := x.TextContent;
  190. end;
  191. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  192. function GetNodeValue(xml: TDOMNode; const aName: WideString; const aDefault: DOMString): DOMString;
  193. var x: TDOMNode;
  194. begin
  195. x := xml.FindNode(aName);
  196. if not Assigned(x)
  197. then result := aDefault
  198. else result := x.TextContent;
  199. end;
  200. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  201. function GetNodeAttrib(xml: TDOMNode; const aName: WideString): DOMString;
  202. var x: TDOMNode;
  203. begin
  204. if xml.HasAttributes then begin
  205. x := xml.Attributes.GetNamedItem(aName);
  206. if Assigned(x) then begin
  207. result := x.TextContent;
  208. exit;
  209. end;
  210. end;
  211. raise XmlException.Create(xml.NodeName + ' without ''' + aName + ''' attribute', xml);
  212. end;
  213. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  214. function GetNodeAttrib(xml: TDOMNode; const aName: WideString; const aDefault: DOMString): DOMString;
  215. var x: TDOMNode;
  216. begin
  217. result := aDefault;
  218. if xml.HasAttributes then begin
  219. x := xml.Attributes.GetNamedItem(aName);
  220. if Assigned(x) then
  221. result := x.TextContent;
  222. end;
  223. end;
  224. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  225. //XmlException//////////////////////////////////////////////////////////////////////////////////////////////////////////
  226. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  227. constructor XmlException.Create(const aMsg: WideString; const aXml: TDOMNode);
  228. begin
  229. inherited Create(String(aMsg + ': ' + aXml.TextContent));
  230. xml := aXml;
  231. end;
  232. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  233. //THeaderGenerator.TvkObjectList////////////////////////////////////////////////////////////////////////////////////////
  234. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  235. function THeaderGenerator.TvkObjectList.FindObj(const aName: DOMstring; const aTypes: TvkObjectTypes; out aObject): Boolean;
  236. var
  237. o: TvkObject;
  238. begin
  239. if (aName = '') then
  240. raise Exception.Create('empty name');
  241. result := true;
  242. TvkObject(aObject) := nil;
  243. for o in self do begin
  244. if (o.VkType in aTypes) and (o.Name = aName) then begin
  245. TvkObject(aObject) := o;
  246. exit;
  247. end;
  248. end;
  249. result := false;
  250. end;
  251. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  252. procedure THeaderGenerator.TvkObjectList.MarkObj(const aName: DOMstring; const aTypes: TvkObjectTypes;
  253. const aMark: Integer);
  254. var o: TvkObject;
  255. begin
  256. if FindObj(aName, aTypes, o)
  257. then o.Mark := aMark
  258. else WriteResolveWarning(aName);
  259. end;
  260. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  261. //THeaderGenerator.TvkObject////////////////////////////////////////////////////////////////////////////////////////////
  262. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  263. procedure THeaderGenerator.TvkObject.SetMark(aValue: Integer);
  264. begin
  265. if (fMark <> 0) then
  266. exit;
  267. fMark := aValue;
  268. DoMark(fMark);
  269. end;
  270. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  271. procedure THeaderGenerator.TvkObject.DoMark(const aMark: Integer);
  272. begin
  273. WriteLn(Format(' %-10s%-50s marked for generation', [FormatType(fType), fName]));
  274. end;
  275. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  276. procedure THeaderGenerator.TvkObject.AddCommentFromXml(xml: TDOMNode);
  277. begin
  278. xml := xml.FindNode('comment');
  279. if Assigned(xml) then
  280. fComment := xml.TextContent;
  281. end;
  282. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  283. constructor THeaderGenerator.TvkObject.Create(const aType: TvkObjectType);
  284. begin
  285. inherited Create;
  286. fType := aType;
  287. end;
  288. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  289. class function THeaderGenerator.TvkObject.CreateFromXml(const xml: TDOMNode): THeaderGenerator.TvkObject;
  290. var
  291. s: DOMString;
  292. x: TDOMNode;
  293. begin
  294. result := nil;
  295. if (xml.NodeName = 'type') and xml.HasAttributes then begin
  296. x := xml.Attributes.GetNamedItem('category');
  297. if not Assigned(x) then
  298. exit;
  299. s := x.TextContent;
  300. if (s = 'basetype') or (s = 'bitmask') then
  301. result := TvkTypeSimple.CreateFromXml(xml)
  302. else if (s = 'handle') then
  303. result := TvkTypeHandle.CreateFromXml(xml)
  304. else if (s = 'funcpointer') then
  305. result := TvkTypeFunctionPtr.CreateFromXml(xml)
  306. else if (s = 'struct') or (s = 'union') then
  307. result := TvkTypeStruct.CreateFromXml(xml);
  308. end else if (xml.NodeName = 'command') then
  309. result := TvkCommand.CreateFromXml(xml);
  310. end;
  311. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  312. //THeaderGenerator.TvkTypeSimple////////////////////////////////////////////////////////////////////////////////////////
  313. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  314. procedure THeaderGenerator.TvkTypeSimple.DoMark(const aMark: Integer);
  315. begin
  316. inherited DoMark(aMark);
  317. if (fParent <> '') and Assigned(fList) then
  318. fList.MarkObj(fParent, VK_OBJECT_TYPES, aMark);
  319. end;
  320. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  321. class function THeaderGenerator.TvkTypeSimple.CreateFromXml(const xml: TDOMNode): THeaderGenerator.TvkTypeSimple;
  322. begin
  323. result := TvkTypeSimple.Create(otType);
  324. try
  325. result.Name := GetNodeValue(xml, 'name');
  326. result.Parent := GetNodeValue(xml, 'type');
  327. except
  328. FreeAndNil(result);
  329. raise;
  330. end;
  331. end;
  332. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  333. //THeaderGenerator.TvkTypeHandle////////////////////////////////////////////////////////////////////////////////////////
  334. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  335. class function THeaderGenerator.TvkTypeHandle.CreateFromXml(const xml: TDOMNode): THeaderGenerator.TvkTypeHandle;
  336. begin
  337. result := TvkTypeHandle.Create(otHandle);
  338. try
  339. result.Name := GetNodeValue(xml, 'name');
  340. result.Parent := GetNodeValue(xml, 'parent', 'VkHandle');
  341. result.NonDispatchable := (GetNodeValue(xml, 'type', '') = 'VK_DEFINE_NON_DISPATCHABLE_HANDLE');
  342. except
  343. FreeAndNil(result);
  344. raise;
  345. end;
  346. end;
  347. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  348. procedure THeaderGenerator.TvkTypeFunction.DoMark(const aMark: Integer);
  349. var a: TArgument;
  350. begin
  351. inherited DoMark(aMark);
  352. if Assigned(fList) then begin
  353. fList.MarkObj(fReturnValue.Typ, VK_OBJECT_TYPES, aMark);
  354. for a in fArguments do
  355. fList.MarkObj(a.Typ, VK_OBJECT_TYPES, aMark);
  356. end;
  357. end;
  358. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  359. //THeaderGenerator.TvkTypeFunction///////////////////////////////////////////////////////////////////////////////////////
  360. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  361. constructor THeaderGenerator.TvkTypeFunction.Create(const aType: TvkObjectType);
  362. begin
  363. inherited Create(aType);
  364. fReturnValue := TArgument.Create;
  365. fArguments := TArgumentList.Create;
  366. end;
  367. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  368. destructor THeaderGenerator.TvkTypeFunction.Destroy;
  369. begin
  370. FreeAndNil(fReturnValue);
  371. FreeAndNil(fArguments);
  372. inherited Destroy;
  373. end;
  374. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  375. //THeaderGenerator.TvkTypeFunctionPtr///////////////////////////////////////////////////////////////////////////////////
  376. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  377. class function THeaderGenerator.TvkTypeFunctionPtr.CreateFromXml(const xml: TDOMNode): THeaderGenerator.TvkTypeFunctionPtr;
  378. var
  379. x, p: TDOMNode;
  380. a: TArgument;
  381. rx: TRegExpr;
  382. begin
  383. result := TvkTypeFunctionPtr.Create(otFuncPtr);
  384. try
  385. x := xml.FindNode('name');
  386. if not Assigned(x) then
  387. raise XmlException.Create(xml.NodeName + ' witout child ''name''', xml);
  388. result.Name := x.TextContent;
  389. p := x.PreviousSibling;
  390. if not Assigned(p) then
  391. raise XmlException.Create(xml.NodeName + ' witout return type', xml);
  392. rx := TRegExpr.Create('typedef\s+((const)?)\s*([-_A-Za-z0-9\s]+?)\s*(\*?)\s*\(');
  393. try
  394. if not rx.Exec(String(p.TextContent)) then
  395. raise XmlException.Create('unable to parse return type of function pointer', xml);
  396. result.ReturnValue.IsConst := (Trim(rx.Match[1]) = 'const');
  397. result.ReturnValue.Typ := WideString(Trim(rx.Match[3]));
  398. result.ReturnValue.IsPointer := (Trim(rx.Match[4]) = '*');
  399. x := xml.FirstChild;
  400. while Assigned(x) do begin
  401. if (x.NodeName = 'type') then begin
  402. a := TArgument.Create;
  403. try
  404. p := x.PreviousSibling;
  405. if not Assigned(p) then
  406. raise XmlException.Create('unable to parse function pointer arguments', xml);
  407. rx.Expression := '[A-Za-z]*';
  408. a.IsConst := rx.Exec(String(p.TextContent)) and (rx.Match[0] = 'const');
  409. a.Typ := x.TextContent;
  410. p := x.NextSibling;
  411. if not Assigned(p) then
  412. raise XmlException.Create('unable to parse function pointer arguments', xml);
  413. rx.Expression := '(\*?)\s*([-_A-Za-z0-9]+)';
  414. if not rx.Exec(String(p.TextContent)) then
  415. raise XmlException.Create('unable to parse function pointer arguments', xml);
  416. a.IsPointer := (rx.Match[1] = '*');
  417. a.Name := WideString(Trim(rx.Match[2]));
  418. result.Arguments.Add(a);
  419. except
  420. FreeAndNil(a)
  421. end;
  422. end;
  423. x := x.NextSibling;
  424. end;
  425. finally
  426. FreeAndNil(rx);
  427. end;
  428. except
  429. FreeAndNil(result);
  430. raise;
  431. end;
  432. end;
  433. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  434. //THeaderGenerator.TvkCommand///////////////////////////////////////////////////////////////////////////////////////
  435. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  436. class function THeaderGenerator.TvkCommand.CreateFromXml(const xml: TDOMNode): THeaderGenerator.TvkCommand;
  437. procedure ParseProto(const x: TDOMNode);
  438. begin
  439. result.Name := GetNodeValue(x, 'name');
  440. result.ReturnValue.Typ := GetNodeValue(x, 'type');
  441. end;
  442. procedure ParseParam(const x: TDOMNode);
  443. var
  444. p: TDOMNode;
  445. a: TArgument;
  446. begin
  447. a := TArgument.Create;
  448. try
  449. p := x.FindNode('name');
  450. if not Assigned(p) then
  451. raise XmlException.Create('unable to parse command; param without name', xml);
  452. a.Name := p.TextContent;
  453. p := x.FindNode('type');
  454. if not Assigned(p) then
  455. raise XmlException.Create('unable to parse command; param without type', xml);
  456. a.Typ := p.TextContent;
  457. a.IsConst := Assigned(p.PreviousSibling) and (Trim(p.PreviousSibling.TextContent) = 'const');
  458. a.IsPointer := Assigned(p.NextSibling) and (Trim(p.NextSibling.TextContent) = '*');
  459. result.Arguments.Add(a);
  460. except
  461. FreeAndNil(a);
  462. raise;
  463. end;
  464. end;
  465. var
  466. x: TDOMNode;
  467. begin
  468. result := TvkCommand.Create(otCommand);
  469. try
  470. x := xml.FirstChild;
  471. while Assigned(x) do begin
  472. if (x.NodeName = 'proto') then
  473. ParseProto(x)
  474. else if (x.NodeName = 'param') then
  475. ParseParam(x);
  476. x := x.NextSibling;
  477. end;
  478. except
  479. FreeAndNil(result);
  480. raise;
  481. end;
  482. end;
  483. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  484. procedure THeaderGenerator.TvkTypeStruct.DoMark(const aMark: Integer);
  485. var m: TMember;
  486. begin
  487. inherited DoMark(aMark);
  488. if Assigned(fList) then begin
  489. for m in fMember do
  490. fList.MarkObj(m.Typ, VK_OBJECT_TYPES, aMark);
  491. end;
  492. end;
  493. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  494. //THeaderGenerator.TvkTypeStruct////////////////////////////////////////////////////////////////////////////////////////
  495. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  496. constructor THeaderGenerator.TvkTypeStruct.Create(const aType: TvkObjectType);
  497. begin
  498. inherited Create(aType);
  499. fMember := TMemberList.Create;
  500. end;
  501. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  502. destructor THeaderGenerator.TvkTypeStruct.Destroy;
  503. begin
  504. FreeAndNil(fMember);
  505. inherited Destroy;
  506. end;
  507. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  508. class function THeaderGenerator.TvkTypeStruct.CreateFromXml(const xml: TDOMNode): THeaderGenerator.TvkTypeStruct;
  509. var
  510. x, p: TDOMNode;
  511. m: TMember;
  512. rx: TRegExpr;
  513. begin
  514. result := TvkTypeStruct.Create(otStruct);
  515. try
  516. result.Name := GetNodeAttrib(xml, 'name');
  517. result.IsUnion := (GetNodeAttrib(xml, 'category') = 'union');
  518. x := xml.FirstChild;
  519. while Assigned(x) do begin
  520. if (x.NodeName = 'member') then begin
  521. m := TMember.Create;
  522. try
  523. // read name
  524. p := x.FindNode('name');
  525. if not Assigned(p) then
  526. raise XmlException.Create('struct member without name', xml);
  527. m.Name := p.TextContent;
  528. if Assigned(p.NextSibling) then
  529. m.Name := m.Name + p.NextSibling.TextContent;
  530. m.Name := Trim(m.Name);
  531. rx := TRegExpr.Create('([-_A-Za-z0-9]+)\s*\[\s*([0-9]+)\s*\]');
  532. try
  533. if rx.Exec(String(m.Name)) then begin
  534. m.Name := WideString(rx.Match[1]);
  535. m.ArrSize := StrToInt(rx.Match[2]);
  536. end;
  537. finally
  538. FreeAndNil(rx);
  539. end;
  540. // read type
  541. p := x.FindNode('type');
  542. if not Assigned(p) then
  543. raise XmlException.Create('struct member without type', xml);
  544. m.Typ := p.TextContent;
  545. m.IsConst := Assigned(p.PreviousSibling) and (Trim(p.PreviousSibling.TextContent) = 'const');
  546. m.IsPointer := Assigned(p.NextSibling) and (Trim(p.NextSibling.TextContent) = '*');
  547. result.Member.Add(m);
  548. except
  549. FreeAndNil(m);
  550. end;
  551. end;
  552. x := x.NextSibling;
  553. end;
  554. except
  555. FreeAndNil(result);
  556. raise;
  557. end;
  558. end;
  559. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  560. //THeaderGenerator.TvkTypeEnum//////////////////////////////////////////////////////////////////////////////////////////
  561. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  562. constructor THeaderGenerator.TvkTypeEnum.Create(const aType: TvkObjectType);
  563. begin
  564. inherited Create(aType);
  565. fValues := TValueList.Create;
  566. end;
  567. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  568. destructor THeaderGenerator.TvkTypeEnum.Destroy;
  569. begin
  570. FreeAndNil(fValues);
  571. inherited Destroy;
  572. end;
  573. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  574. class function THeaderGenerator.TvkTypeEnum.CreateFromXml(const xml: TDOMNode): THeaderGenerator.TvkTypeEnum;
  575. var
  576. x, p: TDOMNode;
  577. v: TValue;
  578. function StrToValue(s: String): Variant;
  579. var
  580. f: TFormatSettings;
  581. rx: TRegExpr;
  582. begin
  583. f.DecimalSeparator := '.';
  584. rx := TRegExpr.Create;
  585. try
  586. result := Unassigned;
  587. rx.Expression := '^-?(0x)?([0-9A-Fa-f]+)$';
  588. if rx.Exec(s) then
  589. result := StrToInt(rx.Match[1] + rx.Match[2]);
  590. rx.Expression := '^([0-9\.]+)(f|d)?$';
  591. if rx.Exec(s) then begin
  592. result := StrToFloat(rx.Match[1], f);
  593. if (rx.Match[2] = 'd') then
  594. result := Double(result);
  595. end;
  596. rx.Expression := '^\(~0U([L]*)\)$';
  597. if rx.Exec(s) then begin
  598. if (rx.Match[2] = '')
  599. then result := High(Cardinal)
  600. else result := High(UInt64);
  601. end;
  602. if (result = Unassigned) then
  603. raise XmlException.Create(WideString('invalid enum value (' + s + ')'), xml);
  604. finally
  605. FreeAndNil(rx);
  606. end;
  607. end;
  608. begin
  609. result := TvkTypeEnum.Create(otEnum);
  610. try
  611. result.Name := GetNodeAttrib(xml, 'name');
  612. x := xml.FirstChild;
  613. while Assigned(x) do begin
  614. if (x.NodeName = 'enum') then begin
  615. v := TValue.Create;
  616. try
  617. v.Name := GetNodeAttrib(x, 'name');
  618. p := x.Attributes.GetNamedItem('value');
  619. if Assigned(p) then begin
  620. v.IsBit := false;
  621. v.Value := StrToValue(String(p.TextContent));
  622. end else begin
  623. p := x.Attributes.GetNamedItem('bitpos');
  624. if not Assigned(p) then
  625. raise XmlException.Create('enum without value or bitpos', xml);
  626. v.IsBit := false;
  627. v.Value := StrToValue(String(p.TextContent));
  628. end;
  629. result.Values.Add(v);
  630. except
  631. FreeAndNil(v);
  632. raise;
  633. end;
  634. end;
  635. x := x.NextSibling;
  636. end;
  637. except
  638. FreeAndNil(result);
  639. raise;
  640. end;
  641. end;
  642. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  643. //THeaderGenerator//////////////////////////////////////////////////////////////////////////////////////////////////////
  644. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  645. procedure THeaderGenerator.ReadFile(const aFilename: String);
  646. var
  647. fs: TFileStream;
  648. begin
  649. if not FileExists(aFilename) then
  650. raise Exception.Create('file does not exist: ' + aFilename);
  651. fs := TFileStream.Create(aFilename, fmOpenRead);
  652. try
  653. ReadFile(fs);
  654. finally
  655. FreeAndNil(fs);
  656. end;
  657. end;
  658. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  659. procedure THeaderGenerator.ReadFile(const aStream: TStream);
  660. var
  661. xml: TDOMNode;
  662. CurrentMark: Integer;
  663. procedure AddObject(const aObj: TvkObject);
  664. begin
  665. if Assigned(aObj) then begin
  666. fObjects.Add(aObj);
  667. aObj.List := fObjects;
  668. WriteLn(Format(' %-10s%s', [FormatType(aObj.VkType), aObj.Name]));
  669. end;
  670. end;
  671. procedure ParseTypes(const xml: TDOMNode);
  672. var
  673. x: TDOMNode;
  674. begin
  675. x := xml.FirstChild;
  676. while Assigned(x) do begin
  677. AddObject(TvkObject.CreateFromXml(x));
  678. x := x.NextSibling;
  679. end;
  680. end;
  681. procedure EnableFeature(const xml: TDOMNode);
  682. var
  683. x: TDOMNode;
  684. begin
  685. x := xml.FirstChild;
  686. while Assigned(x) do begin
  687. if (x.NodeName = 'require') then
  688. EnableFeature(x)
  689. else if (x.NodeName = 'type') then
  690. fObjects.MarkObj(GetNodeAttrib(x, 'name'), VK_OBJECT_TYPES, CurrentMark)
  691. else if (x.NodeName = 'command') then
  692. fObjects.MarkObj(GetNodeAttrib(x, 'name'), [ otCommand ], CurrentMark);
  693. x := x.NextSibling;
  694. end;
  695. end;
  696. begin
  697. Clear;
  698. ReadXMLFile(fDocument, aStream);
  699. CurrentMark := 1;
  700. WriteLn('read xml data');
  701. xml := fDocument.DocumentElement.FirstChild;
  702. while Assigned(xml) do begin
  703. if (xml.NodeName = 'types') or (xml.NodeName = 'commands') then
  704. ParseTypes(xml)
  705. else if (xml.NodeName = 'enums') then
  706. AddObject(TvkTypeEnum.CreateFromXml(xml))
  707. else if (xml.NodeName = 'comment') then
  708. fComment := xml.TextContent
  709. else if (xml.NodeName = 'feature') then
  710. EnableFeature(xml);
  711. xml := xml.NextSibling;
  712. end;
  713. WriteLn('generate header');
  714. end;
  715. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  716. procedure THeaderGenerator.Clear;
  717. procedure CreateBaseType(const aName: DOMString);
  718. var o: TvkObject;
  719. begin
  720. o := TvkTypeSimple.Create(otType);
  721. try
  722. o.Name := aName;
  723. o.List := fObjects;
  724. fObjects.Add(o);
  725. except
  726. FreeAndNil(o);
  727. raise;
  728. end;
  729. end;
  730. begin
  731. fComment := '';
  732. fObjects.Clear;
  733. CreateBaseType('void');
  734. CreateBaseType('uint16_t');
  735. CreateBaseType('uint32_t');
  736. CreateBaseType('uint64_t');
  737. CreateBaseType('int16_t');
  738. CreateBaseType('int32_t');
  739. CreateBaseType('int64_t');
  740. CreateBaseType('float');
  741. CreateBaseType('double');
  742. CreateBaseType('char');
  743. CreateBaseType('uint8_t');
  744. CreateBaseType('size_t');
  745. CreateBaseType('VkHandle');
  746. end;
  747. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  748. constructor THeaderGenerator.Create;
  749. begin
  750. inherited Create;
  751. fObjects := TvkObjectList.Create;
  752. end;
  753. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  754. destructor THeaderGenerator.Destroy;
  755. begin
  756. FreeAndNil(fObjects);
  757. FreeAndNil(fDocument);
  758. inherited Destroy;
  759. end;
  760. end.