You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

1489 lines
52 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. otEnum,
  15. otConst,
  16. otFuncPtr,
  17. otStruct,
  18. otCommand);
  19. TvkObjectTypes = set of TvkObjectType;
  20. TvkObject = class;
  21. TvkObjectList = class(specialize TFPGObjectList<TvkObject>)
  22. public
  23. function IndexOfObj(const aName: DOMstring; const aTypes: TvkObjectTypes): Integer;
  24. function FindObj(const aName: DOMstring; const aTypes: TvkObjectTypes; out aObject): Boolean;
  25. procedure MarkObj(const aName: DOMstring; const aTypes: TvkObjectTypes; const aMark: Integer);
  26. function GetPascalName(const aName: DOMString; const aPointer: Integer; const aArrSize: WideString = ''): WideString;
  27. end;
  28. ////////////////////////////////////////////////////////////////////////////////////////////
  29. TvkObject = class(TObject)
  30. private
  31. fType: TvkObjectType;
  32. fName: DOMString;
  33. fComment: DOMString;
  34. fMark: Integer;
  35. fConstGenerated: Boolean;
  36. fTypeGenerated: Boolean;
  37. fPtrGenerated: Boolean;
  38. fVarGenerated: Boolean;
  39. fImplGenerated: Boolean;
  40. fList: TvkObjectList;
  41. private
  42. procedure SetMark(aValue: Integer);
  43. protected
  44. function GetDependencyOrder: Integer; virtual;
  45. procedure DoMark(const aMark: Integer); virtual;
  46. procedure GenPascalName(var aName: WideString; const aPointer: Integer; const aArrSize: WideString); virtual;
  47. public
  48. property VkType: TvkObjectType read fType;
  49. property Name: DOMString read fName write fName;
  50. property Comment: DOMString read fComment write fComment;
  51. property Mark: Integer read fMark write SetMark;
  52. property ConstGenerated: Boolean read fConstGenerated;
  53. property TypeGenerated: Boolean read fTypeGenerated;
  54. property PtrGenerated: Boolean read fPtrGenerated;
  55. property VarGenerated: Boolean read fVarGenerated;
  56. property ImplGenerated: Boolean read fImplGenerated;
  57. property DependencyOrder: Integer read GetDependencyOrder;
  58. property List: TvkObjectList read fList write fList;
  59. procedure AddCommentFromXml(xml: TDOMNode);
  60. function GetPascalName(const aPointer: Integer; const aArrSize: WideString): WideString;
  61. function GenerateConst(const aCode: TStrings): Boolean; virtual;
  62. function GenerateType(const aCode: TStrings): Boolean; virtual;
  63. function GeneratePtr(const aCode: TStrings): Boolean; virtual;
  64. function GenerateVar(const aCode: TStrings): Boolean; virtual;
  65. function GenerateImpl(const aCode: TStrings): Boolean; virtual;
  66. constructor Create(const aType: TvkObjectType);
  67. public
  68. class function CreateFromXml(const xml: TDOMNode): THeaderGenerator.TvkObject;
  69. end;
  70. ////////////////////////////////////////////////////////////////////////////////////////////
  71. TvkTypeSimple = class(TvkObject)
  72. private
  73. fParent: DOMString;
  74. fAlias: DOMString;
  75. protected
  76. function GetDependencyOrder: Integer; override;
  77. procedure DoMark(const aMark: Integer); override;
  78. procedure GenPascalName(var aName: WideString; const aPointer: Integer; const aArrSize: WideString); override;
  79. public
  80. property Parent: DOMString read fParent write fParent;
  81. property Alias: DOMString read fAlias write fAlias;
  82. function GenerateType(const aCode: TStrings): Boolean; override;
  83. function GeneratePtr(const aCode: TStrings): Boolean; override;
  84. public
  85. class function CreateFromXml(const xml: TDOMNode): THeaderGenerator.TvkTypeSimple;
  86. end;
  87. ////////////////////////////////////////////////////////////////////////////////////////////
  88. TvkTypeHandle = class(TvkTypeSimple)
  89. private
  90. fNonDispatchable: Boolean;
  91. public
  92. property NonDispatchable: Boolean read fNonDispatchable write fNonDispatchable;
  93. public
  94. class function CreateFromXml(const xml: TDOMNode): THeaderGenerator.TvkTypeHandle;
  95. end;
  96. ////////////////////////////////////////////////////////////////////////////////////////////
  97. TvkTypeFunction = class(TvkObject)
  98. private type
  99. TArgument = class(TObject)
  100. Typ: DOMString;
  101. Name: DOMString;
  102. IsPointer: Integer;
  103. IsConst: Boolean;
  104. end;
  105. TArgumentList = specialize TFPGObjectList<TArgument>;
  106. private
  107. fReturnValue: TArgument;
  108. fArguments: TArgumentList;
  109. protected
  110. function GetDependencyOrder: Integer; override;
  111. procedure DoMark(const aMark: Integer); override;
  112. procedure GenPascalName(var aName: WideString; const aPointer: Integer; const aArrSize: WideString); override;
  113. procedure GenerateFunctionPtr(const aCode: TStrings);
  114. public
  115. property ReturnValue: TArgument read fReturnValue;
  116. property Arguments: TArgumentList read fArguments;
  117. constructor Create(const aType: TvkObjectType);
  118. destructor Destroy; override;
  119. end;
  120. ////////////////////////////////////////////////////////////////////////////////////////////
  121. TvkTypeFunctionPtr = class(TvkTypeFunction)
  122. public
  123. function GenerateType(const aCode: TStrings): Boolean; override;
  124. public
  125. class function CreateFromXml(const xml: TDOMNode): THeaderGenerator.TvkTypeFunctionPtr;
  126. end;
  127. ////////////////////////////////////////////////////////////////////////////////////////////
  128. TvkCommand = class(TvkTypeFunction)
  129. public
  130. function GenerateType(const aCode: TStrings): Boolean; override;
  131. function GenerateVar(const aCode: TStrings): Boolean; override;
  132. function GenerateImpl(const aCode: TStrings): Boolean; override;
  133. public
  134. class function CreateFromXml(const xml: TDOMNode): THeaderGenerator.TvkCommand;
  135. end;
  136. ////////////////////////////////////////////////////////////////////////////////////////////
  137. TvkTypeStruct = class(TvkObject)
  138. private type
  139. TMember = class(TObject)
  140. Typ: DOMString;
  141. Name: DOMString;
  142. ArrSize: DOMString;
  143. IsPointer: Integer;
  144. IsConst: Boolean;
  145. end;
  146. TMemberList = specialize TFPGObjectList<TMember>;
  147. private
  148. fIsUnion: Boolean;
  149. fMember: TMemberList;
  150. protected
  151. function GetDependencyOrder: Integer; override;
  152. procedure DoMark(const aMark: Integer); override;
  153. procedure GenPascalName(var aName: WideString; const aPointer: Integer; const aArrSize: WideString); override;
  154. public
  155. property Member: TMemberList read fMember;
  156. property IsUnion: Boolean read fIsUnion write fIsUnion;
  157. function GenerateType(const aCode: TStrings): Boolean; override;
  158. constructor Create(const aType: TvkObjectType);
  159. destructor Destroy; override;
  160. public
  161. class function CreateFromXml(const xml: TDOMNode): THeaderGenerator.TvkTypeStruct;
  162. end;
  163. ////////////////////////////////////////////////////////////////////////////////////////////
  164. TvkTypeEnum = class(TvkObject)
  165. private type
  166. TValue = class(TObject)
  167. Name: DOMString;
  168. Value: Variant;
  169. IsBit: Boolean;
  170. end;
  171. TValueList = specialize TFPGObjectList<TValue>;
  172. private
  173. fValues: TValueList;
  174. protected
  175. procedure GenPascalName(var aName: WideString; const aPointer: Integer; const aArrSize: WideString); override;
  176. public
  177. property Values: TValueList read fValues;
  178. function GenerateConst(const aCode: TStrings): Boolean; override;
  179. function GenerateType(const aCode: TStrings): Boolean; override;
  180. constructor Create(const aType: TvkObjectType);
  181. destructor Destroy; override;
  182. public
  183. class function CreateFromXml(const xml: TDOMNode): THeaderGenerator.TvkTypeEnum;
  184. end;
  185. private const
  186. VK_OBJECT_TYPES: TvkObjectTypes = [ otType, otHandle, otFuncPtr, otStruct, otEnum ];
  187. private
  188. fDocument: TXMLDocument;
  189. fObjects: TvkObjectList;
  190. fOutputFile: String;
  191. fTemplateFile: String;
  192. public
  193. property OutputFile: String read fOutputFile write fOutputFile;
  194. property TemplateFile: String read fTemplateFile write fTemplateFile;
  195. procedure ReadFile(const aFilename: String);
  196. procedure ReadFile(const aStream: TStream);
  197. procedure Clear;
  198. constructor Create;
  199. destructor Destroy; override;
  200. end;
  201. implementation
  202. uses
  203. Math, XMLRead, RegExpr;
  204. type
  205. XmlException = class(Exception)
  206. public
  207. xml: TDOMNode;
  208. constructor Create(const aMsg: WideString; const aXml: TDOMNode);
  209. end;
  210. const
  211. COMMENT_HEAD = '{ ============================================================================' + sLineBreak;
  212. COMMENT_BREAK = sLineBreak + sLineBreak + '==============================================================================' + sLineBreak + sLineBreak;
  213. COMMENT_TAIL = sLineBreak + '============================================================================ }';
  214. COMMENT_CONTENT =
  215. 'This file is autogenerated from vk.xml' + sLineBreak +
  216. '' + sLineBreak +
  217. 'You may retrieve the latest version of this file at the Delphi OpenGL' + sLineBreak +
  218. 'Community home page, located at http://www.delphigl.com/' + sLineBreak +
  219. '' + sLineBreak +
  220. 'The contents of this file are used with permission, subject to' + sLineBreak +
  221. 'the Mozilla Public License Version 1.1 (the "License"); you may' + sLineBreak +
  222. 'not use this file except in compliance with the License. You may' + sLineBreak +
  223. 'obtain a copy of the License at' + sLineBreak +
  224. 'http://www.mozilla.org/MPL/MPL-1.1.html' + sLineBreak +
  225. '' + sLineBreak +
  226. 'Software distributed under the License is distributed on an' + sLineBreak +
  227. '"AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or' + sLineBreak +
  228. 'implied. See the License for the specific language governing' + sLineBreak +
  229. 'rights and limitations under the License.' + sLineBreak;
  230. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  231. function PointerCount(const aStr: AnsiString): Integer;
  232. var i: Integer;
  233. begin
  234. result := 0;
  235. i := Length(aStr);
  236. while (i > 0) do begin
  237. if (aStr[i] = '*') then
  238. inc(result);
  239. dec(i);
  240. end;
  241. end;
  242. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  243. function PrepareName(const aName, aType: WideString): WideString;
  244. var rx: TRegExpr;
  245. begin
  246. result := aName;
  247. if (result = 'type') then begin
  248. rx := TRegExpr.Create('^(T|P)?(Vk)?(.)');
  249. try
  250. if rx.Exec(String(aType))
  251. then result := WideString(LowerCase(rx.Match[3]) + 'Type')
  252. else result := 'mType';
  253. finally
  254. FreeAndNil(rx);
  255. end;
  256. end;
  257. end;
  258. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  259. function CompareVkObjDependency(const aItem1, aItem2: THeaderGenerator.TvkObject): Integer;
  260. var
  261. w1, w2: WideString;
  262. begin
  263. result := (aItem1.DependencyOrder - aItem2.DependencyOrder);
  264. if (result = 0) then begin
  265. w1 := aItem1.Name;
  266. w2 := aItem2.Name;
  267. result := strcomp(PWideChar(w1), PWideChar(w2));
  268. end;
  269. end;
  270. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  271. function FormatType(const aType: THeaderGenerator.TvkObjectType): WideString;
  272. begin
  273. case aType of
  274. otType: result := 'TYPE';
  275. otHandle: result := 'HANDLE';
  276. otFuncPtr: result := 'FUNCPTR';
  277. otStruct: result := 'STRUCT';
  278. otEnum: result := 'ENUM';
  279. otConst: result := 'CONSTANT';
  280. otCommand: result := 'COMMAND';
  281. else
  282. result := '';
  283. end;
  284. end;
  285. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  286. procedure WriteResolveWarning(const aName: DOMString);
  287. begin
  288. WriteLn('WARNING! unable to resolve identifier: ' + aName);
  289. end;
  290. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  291. function GetNodeValue(xml: TDOMNode; const aName: WideString): DOMString;
  292. var x: TDOMNode;
  293. begin
  294. x := xml.FindNode(aName);
  295. if not Assigned(x) then
  296. raise XmlException.Create(xml.NodeName + ' witout child ''' + aName + '''', xml);
  297. result := x.TextContent;
  298. end;
  299. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  300. function GetNodeValue(xml: TDOMNode; const aName: WideString; const aDefault: DOMString): DOMString;
  301. var x: TDOMNode;
  302. begin
  303. x := xml.FindNode(aName);
  304. if not Assigned(x)
  305. then result := aDefault
  306. else result := x.TextContent;
  307. end;
  308. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  309. function GetNodeAttrib(xml: TDOMNode; const aName: WideString): DOMString;
  310. var x: TDOMNode;
  311. begin
  312. if xml.HasAttributes then begin
  313. x := xml.Attributes.GetNamedItem(aName);
  314. if Assigned(x) then begin
  315. result := x.TextContent;
  316. exit;
  317. end;
  318. end;
  319. raise XmlException.Create(xml.NodeName + ' without ''' + aName + ''' attribute', xml);
  320. end;
  321. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  322. function GetNodeAttrib(xml: TDOMNode; const aName: WideString; const aDefault: DOMString): DOMString;
  323. var x: TDOMNode;
  324. begin
  325. result := aDefault;
  326. if xml.HasAttributes then begin
  327. x := xml.Attributes.GetNamedItem(aName);
  328. if Assigned(x) then
  329. result := x.TextContent;
  330. end;
  331. end;
  332. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  333. //XmlException//////////////////////////////////////////////////////////////////////////////////////////////////////////
  334. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  335. constructor XmlException.Create(const aMsg: WideString; const aXml: TDOMNode);
  336. begin
  337. inherited Create(String(aMsg + ': ' + aXml.TextContent));
  338. xml := aXml;
  339. end;
  340. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  341. //THeaderGenerator.TvkObjectList////////////////////////////////////////////////////////////////////////////////////////
  342. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  343. function THeaderGenerator.TvkObjectList.IndexOfObj(const aName: DOMstring; const aTypes: TvkObjectTypes): Integer;
  344. var o: TvkObject;
  345. begin
  346. if (aName = '') then
  347. raise Exception.Create('empty name');
  348. for result := 0 to Count-1 do begin
  349. o := Get(result);
  350. if (o.VkType in aTypes) and (o.Name = aName) then
  351. exit;
  352. end;
  353. result := -1;
  354. end;
  355. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  356. function THeaderGenerator.TvkObjectList.FindObj(const aName: DOMstring; const aTypes: TvkObjectTypes; out aObject): Boolean;
  357. var i: Integer;
  358. begin
  359. i := IndexOfObj(aName, aTypes);
  360. result := (i >= 0);
  361. if result
  362. then TvkObject(aObject) := Get(i)
  363. else TvkObject(aObject) := nil;
  364. end;
  365. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  366. procedure THeaderGenerator.TvkObjectList.MarkObj(const aName: DOMstring; const aTypes: TvkObjectTypes; const aMark: Integer);
  367. var o: TvkObject;
  368. begin
  369. if FindObj(aName, aTypes, o)
  370. then o.Mark := aMark
  371. else WriteResolveWarning(aName);
  372. end;
  373. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  374. function THeaderGenerator.TvkObjectList.GetPascalName(const aName: DOMString; const aPointer: Integer;
  375. const aArrSize: WideString): WideString;
  376. var o: TvkObject;
  377. begin
  378. if FindObj(aName, VK_OBJECT_TYPES, o)
  379. then result := o.GetPascalName(aPointer, aArrSize)
  380. else result := aName;
  381. end;
  382. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  383. //THeaderGenerator.TvkObject////////////////////////////////////////////////////////////////////////////////////////////
  384. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  385. procedure THeaderGenerator.TvkObject.SetMark(aValue: Integer);
  386. begin
  387. if (fMark <> 0) then
  388. exit;
  389. fMark := aValue;
  390. DoMark(fMark);
  391. end;
  392. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  393. function THeaderGenerator.TvkObject.GetDependencyOrder: Integer;
  394. begin
  395. result := 0;
  396. end;
  397. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  398. procedure THeaderGenerator.TvkObject.DoMark(const aMark: Integer);
  399. begin
  400. WriteLn(Format(' %-10s%-50s marked for generation', [FormatType(fType), fName]));
  401. end;
  402. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  403. procedure THeaderGenerator.TvkObject.GenPascalName(var aName: WideString; const aPointer: Integer; const aArrSize: WideString);
  404. var
  405. i: Integer;
  406. begin
  407. if (aName = '') then begin
  408. aName := fName;
  409. if (aName = 'void') then
  410. aName := 'VkVoid';
  411. for i := 0 to aPointer-1 do
  412. aName := 'P' + aName;
  413. end;
  414. if (aName = 'VkVoid') then
  415. raise Exception.Create('void can not be used as type');
  416. if (aArrSize <> '') then begin
  417. if TryStrToInt(String(aArrSize), i)
  418. then aName := WideString(Format('array[0..%d] of %s', [i, aName]))
  419. else aName := WideString(Format('array[0..%s-1] of %s', [aArrSize, aName]));
  420. end;
  421. end;
  422. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  423. procedure THeaderGenerator.TvkObject.AddCommentFromXml(xml: TDOMNode);
  424. begin
  425. xml := xml.FindNode('comment');
  426. if Assigned(xml) then
  427. fComment := xml.TextContent;
  428. end;
  429. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  430. function THeaderGenerator.TvkObject.GetPascalName(const aPointer: Integer; const aArrSize: WideString): WideString;
  431. begin
  432. result := '';
  433. GenPascalName(result, aPointer, aArrSize);
  434. end;
  435. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  436. function THeaderGenerator.TvkObject.GenerateConst(const aCode: TStrings): Boolean;
  437. begin
  438. result := not fConstGenerated;
  439. if not fConstGenerated then begin
  440. fConstGenerated := true;
  441. WriteLn(Format(' %-10s%-50s constants generated', [FormatType(fType), fName]));
  442. end;
  443. end;
  444. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  445. function THeaderGenerator.TvkObject.GenerateType(const aCode: TStrings): Boolean;
  446. begin
  447. result := not fTypeGenerated;
  448. if not fTypeGenerated then begin
  449. fTypeGenerated := true;
  450. WriteLn(Format(' %-10s%-50s type generated', [FormatType(fType), fName]));
  451. end;
  452. end;
  453. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  454. function THeaderGenerator.TvkObject.GeneratePtr(const aCode: TStrings): Boolean;
  455. begin
  456. result := not fPtrGenerated;
  457. if not fPtrGenerated then begin
  458. fPtrGenerated := true;
  459. WriteLn(Format(' %-10s%-50s pointer type generated', [FormatType(fType), fName]));
  460. end;
  461. end;
  462. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  463. function THeaderGenerator.TvkObject.GenerateVar(const aCode: TStrings): Boolean;
  464. begin
  465. result := not fVarGenerated;
  466. if not fVarGenerated then begin
  467. fVarGenerated := true;
  468. WriteLn(Format(' %-10s%-50s variables generated', [FormatType(fType), fName]));
  469. end;
  470. end;
  471. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  472. function THeaderGenerator.TvkObject.GenerateImpl(const aCode: TStrings): Boolean;
  473. begin
  474. result := not fImplGenerated;
  475. if not fImplGenerated then begin
  476. fImplGenerated := true;
  477. WriteLn(Format(' %-10s%-50s implementation generated', [FormatType(fType), fName]));
  478. end;
  479. end;
  480. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  481. constructor THeaderGenerator.TvkObject.Create(const aType: TvkObjectType);
  482. begin
  483. inherited Create;
  484. fType := aType;
  485. end;
  486. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  487. class function THeaderGenerator.TvkObject.CreateFromXml(const xml: TDOMNode): THeaderGenerator.TvkObject;
  488. var
  489. s: DOMString;
  490. x: TDOMNode;
  491. begin
  492. result := nil;
  493. if (xml.NodeName = 'type') and xml.HasAttributes then begin
  494. x := xml.Attributes.GetNamedItem('category');
  495. if not Assigned(x) then
  496. exit;
  497. s := x.TextContent;
  498. if (s = 'basetype') or (s = 'bitmask') then
  499. result := TvkTypeSimple.CreateFromXml(xml)
  500. else if (s = 'handle') then
  501. result := TvkTypeHandle.CreateFromXml(xml)
  502. else if (s = 'funcpointer') then
  503. result := TvkTypeFunctionPtr.CreateFromXml(xml)
  504. else if (s = 'struct') or (s = 'union') then
  505. result := TvkTypeStruct.CreateFromXml(xml);
  506. end else if (xml.NodeName = 'command') then
  507. result := TvkCommand.CreateFromXml(xml);
  508. end;
  509. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  510. //THeaderGenerator.TvkTypeSimple////////////////////////////////////////////////////////////////////////////////////////
  511. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  512. function THeaderGenerator.TvkTypeSimple.GetDependencyOrder: Integer;
  513. begin
  514. result := inherited GetDependencyOrder;
  515. if Assigned(List) and (fParent <> '') then
  516. result := max(result, List.IndexOfObj(fParent, VK_OBJECT_TYPES) + 1);
  517. end;
  518. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  519. procedure THeaderGenerator.TvkTypeSimple.DoMark(const aMark: Integer);
  520. begin
  521. inherited DoMark(aMark);
  522. if (fParent <> '') and Assigned(fList) then
  523. fList.MarkObj(fParent, VK_OBJECT_TYPES, aMark);
  524. if (fAlias <> '') and Assigned(fList) then
  525. fList.MarkObj(fAlias, VK_OBJECT_TYPES, aMark);
  526. end;
  527. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  528. procedure THeaderGenerator.TvkTypeSimple.GenPascalName(var aName: WideString; const aPointer: Integer; const aArrSize: WideString);
  529. var i: Integer;
  530. begin
  531. if (fAlias <> '')
  532. then aName := fAlias
  533. else aName := fName;
  534. if (aName = 'void') then
  535. aName := 'VkVoid';
  536. for i := 0 to aPointer-1 do
  537. aName := 'P' + aName;
  538. inherited GenPascalName(aName, aPointer, aArrSize);
  539. end;
  540. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  541. function THeaderGenerator.TvkTypeSimple.GenerateType(const aCode: TStrings): Boolean;
  542. begin
  543. result := inherited GenerateType(aCode);
  544. if result and (fParent <> '') and Assigned(List) then
  545. aCode.Add(Format(' %-62s = %s;', [ fName, List.GetPascalName(fParent, 0) ]));
  546. end;
  547. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  548. function THeaderGenerator.TvkTypeSimple.GeneratePtr(const aCode: TStrings): Boolean;
  549. begin
  550. result := inherited GeneratePtr(aCode);
  551. if result and (fParent <> '') and Assigned(List) then begin
  552. aCode.Add(Format(' P%-61s = ^%0:s;', [ fName ]));
  553. aCode.Add(Format(' PP%-60s = ^P%0:s;', [ fName ]));
  554. end;
  555. end;
  556. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  557. class function THeaderGenerator.TvkTypeSimple.CreateFromXml(const xml: TDOMNode): THeaderGenerator.TvkTypeSimple;
  558. begin
  559. result := TvkTypeSimple.Create(otType);
  560. try
  561. result.Name := GetNodeValue(xml, 'name');
  562. result.Parent := GetNodeValue(xml, 'type');
  563. except
  564. FreeAndNil(result);
  565. raise;
  566. end;
  567. end;
  568. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  569. //THeaderGenerator.TvkTypeHandle////////////////////////////////////////////////////////////////////////////////////////
  570. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  571. class function THeaderGenerator.TvkTypeHandle.CreateFromXml(const xml: TDOMNode): THeaderGenerator.TvkTypeHandle;
  572. begin
  573. result := TvkTypeHandle.Create(otHandle);
  574. try
  575. result.Name := GetNodeValue(xml, 'name');
  576. result.Parent := GetNodeValue(xml, 'parent', 'VkHandle');
  577. result.NonDispatchable := (GetNodeValue(xml, 'type', '') = 'VK_DEFINE_NON_DISPATCHABLE_HANDLE');
  578. except
  579. FreeAndNil(result);
  580. raise;
  581. end;
  582. end;
  583. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  584. function THeaderGenerator.TvkTypeFunction.GetDependencyOrder: Integer;
  585. var a: TArgument;
  586. begin
  587. result := inherited GetDependencyOrder;
  588. if not Assigned(List) then
  589. exit;
  590. for a in fArguments do
  591. result := max(result, List.IndexOfObj(a.Typ, VK_OBJECT_TYPES));
  592. end;
  593. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  594. procedure THeaderGenerator.TvkTypeFunction.DoMark(const aMark: Integer);
  595. var a: TArgument;
  596. begin
  597. inherited DoMark(aMark);
  598. if Assigned(fList) then begin
  599. fList.MarkObj(fReturnValue.Typ, VK_OBJECT_TYPES, aMark);
  600. for a in fArguments do
  601. fList.MarkObj(a.Typ, VK_OBJECT_TYPES, aMark);
  602. end;
  603. end;
  604. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  605. procedure THeaderGenerator.TvkTypeFunction.GenPascalName(var aName: WideString; const aPointer: Integer;
  606. const aArrSize: WideString);
  607. var rx: TRegExpr;
  608. begin
  609. if (aPointer > 0) then
  610. Exception.Create('function pointer can not be used as pointer type');
  611. if (aArrSize <> '') then
  612. Exception.Create('function pointer can not be used as array type');
  613. rx := TRegExpr.Create('PFN_([-_A-Za-z0-9]+)');
  614. try
  615. if rx.Exec(String(fName))
  616. then aName := 'T' + WideString(rx.Match[1])
  617. else aName := 'T' + fName;
  618. finally
  619. FreeAndNil(rx);
  620. end;
  621. end;
  622. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  623. procedure THeaderGenerator.TvkTypeFunction.GenerateFunctionPtr(const aCode: TStrings);
  624. var
  625. s: WideString;
  626. i: Integer;
  627. a: TArgument;
  628. begin
  629. s := WideString(Format(' %-50s', [ GetPascalName(0, '') ]));
  630. if (ReturnValue.Typ = 'void')
  631. then s := s + ' = procedure('
  632. else s := s + ' = function (';
  633. for i := 0 to fArguments.Count-1 do begin
  634. a := fArguments[i];
  635. if a.IsConst then
  636. s := s + 'const ';
  637. s := s + PrepareName(a.Name, a.Typ) + ': ' + List.GetPascalName(a.Typ, a.IsPointer);
  638. if (i < fArguments.Count-1) then
  639. s := s + '; ';
  640. end;
  641. s := s + ')';
  642. if (ReturnValue.Typ <> 'void') then
  643. s := s + ': ' + List.GetPascalName(ReturnValue.Typ, ReturnValue.IsPointer);
  644. s := s + '; {$IFDEF VK_CDECL}cdecl{$ELSE}stdcall{$ENDIF};';
  645. aCode.Add(String(s));
  646. end;
  647. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  648. constructor THeaderGenerator.TvkTypeFunction.Create(const aType: TvkObjectType);
  649. begin
  650. inherited Create(aType);
  651. fReturnValue := TArgument.Create;
  652. fArguments := TArgumentList.Create;
  653. end;
  654. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  655. destructor THeaderGenerator.TvkTypeFunction.Destroy;
  656. begin
  657. FreeAndNil(fReturnValue);
  658. FreeAndNil(fArguments);
  659. inherited Destroy;
  660. end;
  661. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  662. //THeaderGenerator.TvkTypeFunctionPtr///////////////////////////////////////////////////////////////////////////////////
  663. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  664. function THeaderGenerator.TvkTypeFunctionPtr.GenerateType(const aCode: TStrings): Boolean;
  665. begin
  666. result := inherited GenerateType(aCode);
  667. if result and Assigned(List) then
  668. GenerateFunctionPtr(aCode);
  669. end;
  670. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  671. class function THeaderGenerator.TvkTypeFunctionPtr.CreateFromXml(const xml: TDOMNode): THeaderGenerator.TvkTypeFunctionPtr;
  672. var
  673. x, p: TDOMNode;
  674. a: TArgument;
  675. rx: TRegExpr;
  676. begin
  677. result := TvkTypeFunctionPtr.Create(otFuncPtr);
  678. try
  679. x := xml.FindNode('name');
  680. if not Assigned(x) then
  681. raise XmlException.Create(xml.NodeName + ' witout child ''name''', xml);
  682. result.Name := x.TextContent;
  683. p := x.PreviousSibling;
  684. if not Assigned(p) then
  685. raise XmlException.Create(xml.NodeName + ' witout return type', xml);
  686. rx := TRegExpr.Create('typedef\s+((const)?)\s*([-_A-Za-z0-9\s]+?)\s*((\*\s*(const)?\s*)*)\s*\(');
  687. try
  688. if not rx.Exec(String(p.TextContent)) then
  689. raise XmlException.Create('unable to parse return type of function pointer', xml);
  690. result.ReturnValue.IsConst := (Trim(rx.Match[1]) = 'const');
  691. result.ReturnValue.Typ := WideString(Trim(rx.Match[3]));
  692. result.ReturnValue.IsPointer := PointerCount(Trim(rx.Match[4]));
  693. x := xml.FirstChild;
  694. while Assigned(x) do begin
  695. if (x.NodeName = 'type') then begin
  696. a := TArgument.Create;
  697. try
  698. p := x.PreviousSibling;
  699. if not Assigned(p) then
  700. raise XmlException.Create('unable to parse function pointer arguments', xml);
  701. rx.Expression := '[A-Za-z]*';
  702. a.IsConst := rx.Exec(String(p.TextContent)) and (rx.Match[0] = 'const');
  703. a.Typ := x.TextContent;
  704. p := x.NextSibling;
  705. if not Assigned(p) then
  706. raise XmlException.Create('unable to parse function pointer arguments', xml);
  707. rx.Expression := '((\*\s*(const)?\s*)*)\s*([-_A-Za-z0-9]+)';
  708. if not rx.Exec(String(p.TextContent)) then
  709. raise XmlException.Create('unable to parse function pointer arguments', xml);
  710. a.IsPointer := PointerCount((rx.Match[1]));
  711. a.Name := WideString(Trim(rx.Match[4]));
  712. result.Arguments.Add(a);
  713. except
  714. FreeAndNil(a)
  715. end;
  716. end;
  717. x := x.NextSibling;
  718. end;
  719. finally
  720. FreeAndNil(rx);
  721. end;
  722. except
  723. FreeAndNil(result);
  724. raise;
  725. end;
  726. end;
  727. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  728. //THeaderGenerator.TvkCommand///////////////////////////////////////////////////////////////////////////////////////
  729. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  730. function THeaderGenerator.TvkCommand.GenerateType(const aCode: TStrings): Boolean;
  731. begin
  732. result := inherited GenerateType(aCode);
  733. if result and Assigned(List) then
  734. GenerateFunctionPtr(aCode);
  735. end;
  736. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  737. function THeaderGenerator.TvkCommand.GenerateVar(const aCode: TStrings): Boolean;
  738. begin
  739. result := inherited GenerateVar(aCode);
  740. if result then
  741. aCode.Add(Format(' %-50s %s = nil;', [ fName + ':', GetPascalName(0, '') ]));
  742. end;
  743. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  744. function THeaderGenerator.TvkCommand.GenerateImpl(const aCode: TStrings): Boolean;
  745. begin
  746. result := inherited GenerateImpl(aCode);
  747. if result then
  748. aCode.Add(Format(' %-50s := vkGetProcAddress(''%0:s'');', [ fName ]));
  749. end;
  750. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  751. class function THeaderGenerator.TvkCommand.CreateFromXml(const xml: TDOMNode): THeaderGenerator.TvkCommand;
  752. procedure ParseProto(const x: TDOMNode);
  753. begin
  754. result.Name := GetNodeValue(x, 'name');
  755. result.ReturnValue.Typ := GetNodeValue(x, 'type');
  756. end;
  757. procedure ParseParam(const x: TDOMNode);
  758. var
  759. p: TDOMNode;
  760. a: TArgument;
  761. rx: TRegExpr;
  762. begin
  763. a := TArgument.Create;
  764. rx := TRegExpr.Create;
  765. try try
  766. p := x.FindNode('name');
  767. if not Assigned(p) then
  768. raise XmlException.Create('unable to parse command; param without name', xml);
  769. a.Name := p.TextContent;
  770. p := x.FindNode('type');
  771. if not Assigned(p) then
  772. raise XmlException.Create('unable to parse command; param without type', xml);
  773. a.Typ := p.TextContent;
  774. a.IsConst := Assigned(p.PreviousSibling) and (Trim(p.PreviousSibling.TextContent) = 'const');
  775. rx.Expression := '((\*\s*(const)?\s*)*)';
  776. if Assigned(p.NextSibling) and rx.Exec(String(p.NextSibling.TextContent)) then
  777. a.IsPointer := PointerCount(rx.Match[0]);
  778. result.Arguments.Add(a);
  779. finally
  780. FreeAndNil(rx);
  781. end;
  782. except
  783. FreeAndNil(a);
  784. raise;
  785. end;
  786. end;
  787. var
  788. x: TDOMNode;
  789. begin
  790. result := TvkCommand.Create(otCommand);
  791. try
  792. x := xml.FirstChild;
  793. while Assigned(x) do begin
  794. if (x.NodeName = 'proto') then
  795. ParseProto(x)
  796. else if (x.NodeName = 'param') then
  797. ParseParam(x);
  798. x := x.NextSibling;
  799. end;
  800. except
  801. FreeAndNil(result);
  802. raise;
  803. end;
  804. end;
  805. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  806. //THeaderGenerator.TvkTypeStruct////////////////////////////////////////////////////////////////////////////////////////
  807. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  808. function THeaderGenerator.TvkTypeStruct.GetDependencyOrder: Integer;
  809. var
  810. m: TMember;
  811. begin
  812. result := inherited GetDependencyOrder;
  813. if not Assigned(List) then
  814. exit;
  815. for m in fMember do
  816. result := max(result, List.IndexOfObj(m.Typ, VK_OBJECT_TYPES) + 1);
  817. end;
  818. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  819. procedure THeaderGenerator.TvkTypeStruct.DoMark(const aMark: Integer);
  820. var m: TMember;
  821. begin
  822. inherited DoMark(aMark);
  823. if Assigned(fList) then begin
  824. for m in fMember do
  825. fList.MarkObj(m.Typ, VK_OBJECT_TYPES, aMark);
  826. end;
  827. end;
  828. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  829. procedure THeaderGenerator.TvkTypeStruct.GenPascalName(var aName: WideString; const aPointer: Integer; const aArrSize: WideString);
  830. var i: Integer;
  831. begin
  832. if (aPointer > 0) then begin
  833. aName := fName;
  834. for i := 0 to aPointer-1 do
  835. aName := 'P' + aName;
  836. end else
  837. aName := 'T' + fName;
  838. inherited GenPascalName(aName, aPointer, aArrSize);
  839. end;
  840. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  841. function THeaderGenerator.TvkTypeStruct.GenerateType(const aCode: TStrings): Boolean;
  842. var
  843. prefix, postfix: String;
  844. i, indent: Integer;
  845. m: TMember;
  846. begin
  847. result := inherited GenerateType(aCode);
  848. result := inherited GeneratePtr(aCode) or result;
  849. if result and Assigned(List) then begin
  850. postfix := ';';
  851. indent := 50;
  852. aCode.Add(' T%s = record', [ fName ]);
  853. if IsUnion then begin
  854. aCode.Add(' case Integer of');
  855. postfix := ');';
  856. indent := 42;
  857. end;
  858. for i := 0 to fMember.Count-1 do begin
  859. m := fMember[i];
  860. if IsUnion
  861. then prefix := Format(' %.3d: (', [ i ])
  862. else prefix := ' ';
  863. aCode.Add(Format('%s%-*s%s%s', [ prefix, indent, PrepareName(m.Name, m.Typ) + ': ', List.GetPascalName(m.Typ, m.IsPointer, m.ArrSize), postfix ]));
  864. end;
  865. aCode.Add(' end;');
  866. aCode.Add(' P%s = ^T%0:s;', [ fName ]);
  867. aCode.Add(' PP%s = ^P%0:s;', [ fName ]);
  868. aCode.Add('');
  869. end;
  870. end;
  871. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  872. //THeaderGenerator.TvkTypeStruct////////////////////////////////////////////////////////////////////////////////////////
  873. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  874. constructor THeaderGenerator.TvkTypeStruct.Create(const aType: TvkObjectType);
  875. begin
  876. inherited Create(aType);
  877. fMember := TMemberList.Create;
  878. end;
  879. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  880. destructor THeaderGenerator.TvkTypeStruct.Destroy;
  881. begin
  882. FreeAndNil(fMember);
  883. inherited Destroy;
  884. end;
  885. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  886. class function THeaderGenerator.TvkTypeStruct.CreateFromXml(const xml: TDOMNode): THeaderGenerator.TvkTypeStruct;
  887. var
  888. x, p: TDOMNode;
  889. m: TMember;
  890. rx: TRegExpr;
  891. begin
  892. result := TvkTypeStruct.Create(otStruct);
  893. try
  894. result.Name := GetNodeAttrib(xml, 'name');
  895. result.IsUnion := (GetNodeAttrib(xml, 'category') = 'union');
  896. x := xml.FirstChild;
  897. while Assigned(x) do begin
  898. if (x.NodeName = 'member') then begin
  899. m := TMember.Create;
  900. rx := TRegExpr.Create('');
  901. try try
  902. // read name
  903. p := x.FindNode('name');
  904. if not Assigned(p) then
  905. raise XmlException.Create('struct member without name', xml);
  906. m.Name := p.TextContent;
  907. p := p.NextSibling;
  908. while Assigned(p) do begin
  909. m.Name := m.Name + p.TextContent;
  910. p := p.NextSibling;
  911. end;
  912. m.Name := Trim(m.Name);
  913. rx.Expression := '([-_A-Za-z0-9]+)\s*\[\s*([-_A-Za-z0-9]+)\s*\]';
  914. if rx.Exec(String(m.Name)) then begin
  915. m.Name := WideString(rx.Match[1]);
  916. m.ArrSize := WideString(rx.Match[2]);
  917. end;
  918. // read type
  919. p := x.FindNode('type');
  920. if not Assigned(p) then
  921. raise XmlException.Create('struct member without type', xml);
  922. m.Typ := p.TextContent;
  923. m.IsConst := Assigned(p.PreviousSibling) and (Trim(p.PreviousSibling.TextContent) = 'const');
  924. rx.Expression := '((\*\s*(const)?\s*)*)';
  925. if Assigned(p.NextSibling) and rx.Exec(String(p.NextSibling.TextContent)) then
  926. m.IsPointer := PointerCount(rx.Match[0]);
  927. result.Member.Add(m);
  928. finally
  929. FreeAndNil(rx);
  930. end;
  931. except
  932. FreeAndNil(m);
  933. end;
  934. end;
  935. x := x.NextSibling;
  936. end;
  937. except
  938. FreeAndNil(result);
  939. raise;
  940. end;
  941. end;
  942. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  943. //THeaderGenerator.TvkTypeEnum//////////////////////////////////////////////////////////////////////////////////////////
  944. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  945. procedure THeaderGenerator.TvkTypeEnum.GenPascalName(var aName: WideString; const aPointer: Integer; const aArrSize: WideString);
  946. var i: Integer;
  947. begin
  948. if (fName = '') then
  949. raise Exception.Create('enum with empty name');
  950. if (aPointer > 0) then begin
  951. aName := fName;
  952. for i := 0 to aPointer-1 do
  953. aName := 'P' + aName;
  954. end else
  955. aName := 'T' + fName;
  956. inherited GenPascalName(aName, aPointer, aArrSize);
  957. end;
  958. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  959. function THeaderGenerator.TvkTypeEnum.GenerateConst(const aCode: TStrings): Boolean;
  960. var
  961. value: String;
  962. i: Integer;
  963. v: TValue;
  964. begin
  965. result := inherited GenerateConst(aCode);
  966. if result and (VkType = otConst) then begin
  967. for i := 0 to fValues.Count-1 do begin
  968. v := fValues[i];
  969. if v.IsBit
  970. then value := Format('(1 shl %s)', [ IntToStr(v.Value) ])
  971. else value := v.Value;
  972. aCode.Add(Format(' %-62s = %s;', [ v.Name, value ]));
  973. end;
  974. aCode.Add('');
  975. end;
  976. end;
  977. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  978. function THeaderGenerator.TvkTypeEnum.GenerateType(const aCode: TStrings): Boolean;
  979. var
  980. value: String;
  981. i: Integer;
  982. v: TValue;
  983. begin
  984. result := inherited GenerateType(aCode);
  985. if result and (VkType = otEnum) then begin
  986. aCode.Add(Format(' T%s = (', [ fName ]));
  987. for i := 0 to fValues.Count-1 do begin
  988. v := fValues[i];
  989. if v.IsBit
  990. then value := Format('(1 shl %s)', [ IntToStr(v.Value) ])
  991. else value := v.Value;
  992. aCode.Add(Format(' %-60s = %s', [ v.Name, value ]));
  993. if (i < fValues.Count-1) then
  994. aCode[aCode.Count-1] := aCode[aCode.Count-1] + ',';
  995. end;
  996. aCode.Add(' );');
  997. aCode.Add(Format(' P%s = ^T%0:s;', [ fName ]));
  998. aCode.Add('');
  999. end;
  1000. end;
  1001. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1002. constructor THeaderGenerator.TvkTypeEnum.Create(const aType: TvkObjectType);
  1003. begin
  1004. inherited Create(aType);
  1005. fValues := TValueList.Create;
  1006. end;
  1007. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1008. destructor THeaderGenerator.TvkTypeEnum.Destroy;
  1009. begin
  1010. FreeAndNil(fValues);
  1011. inherited Destroy;
  1012. end;
  1013. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1014. class function THeaderGenerator.TvkTypeEnum.CreateFromXml(const xml: TDOMNode): THeaderGenerator.TvkTypeEnum;
  1015. var
  1016. x, p: TDOMNode;
  1017. v: TValue;
  1018. function StrToValue(s: String): Variant;
  1019. var
  1020. f: TFormatSettings;
  1021. rx: TRegExpr;
  1022. begin
  1023. f.DecimalSeparator := '.';
  1024. rx := TRegExpr.Create;
  1025. try
  1026. result := Unassigned;
  1027. rx.Expression := '^-?([0-9]+)$';
  1028. if rx.Exec(s) then
  1029. result := StrToInt(rx.Match[0]);
  1030. rx.Expression := '^0x([0-9A-Fa-f]+)$';
  1031. if rx.Exec(s) then
  1032. result := '$' + rx.Match[1];
  1033. rx.Expression := '^([0-9\.]+)(f|d)?$';
  1034. if rx.Exec(s) then begin
  1035. result := StrToFloat(rx.Match[1], f);
  1036. if (rx.Match[2] = 'd') then
  1037. result := Double(result);
  1038. end;
  1039. rx.Expression := '^\(~0U([L]*)\)$';
  1040. if rx.Exec(s) then begin
  1041. if (rx.Match[2] = '')
  1042. then result := '$' + IntToHex(High(UInt32), 2 * sizeof(UInt32))
  1043. else result := '$' + IntToHex(High(UInt64), 2 * sizeof(UInt64));
  1044. end;
  1045. if (result = Unassigned) then
  1046. raise XmlException.Create(WideString('invalid enum value (' + s + ')'), xml);
  1047. finally
  1048. FreeAndNil(rx);
  1049. end;
  1050. end;
  1051. begin
  1052. x := xml.Attributes.GetNamedItem('type');
  1053. if Assigned(x)
  1054. then result := TvkTypeEnum.Create(otEnum)
  1055. else result := TvkTypeEnum.Create(otConst);
  1056. try
  1057. result.Name := GetNodeAttrib(xml, 'name');
  1058. x := xml.FirstChild;
  1059. while Assigned(x) do begin
  1060. if (x.NodeName = 'enum') then begin
  1061. v := TValue.Create;
  1062. try
  1063. v.Name := GetNodeAttrib(x, 'name');
  1064. p := x.Attributes.GetNamedItem('value');
  1065. if Assigned(p) then begin
  1066. v.IsBit := false;
  1067. v.Value := StrToValue(String(p.TextContent));
  1068. end else begin
  1069. p := x.Attributes.GetNamedItem('bitpos');
  1070. if not Assigned(p) then
  1071. raise XmlException.Create('enum without value or bitpos', xml);
  1072. v.IsBit := true;
  1073. v.Value := StrToValue(String(p.TextContent));
  1074. end;
  1075. result.Values.Add(v);
  1076. except
  1077. FreeAndNil(v);
  1078. raise;
  1079. end;
  1080. end;
  1081. x := x.NextSibling;
  1082. end;
  1083. except
  1084. FreeAndNil(result);
  1085. raise;
  1086. end;
  1087. end;
  1088. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1089. //THeaderGenerator//////////////////////////////////////////////////////////////////////////////////////////////////////
  1090. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1091. procedure THeaderGenerator.ReadFile(const aFilename: String);
  1092. var
  1093. fs: TFileStream;
  1094. begin
  1095. if not FileExists(aFilename) then
  1096. raise Exception.Create('file does not exist: ' + aFilename);
  1097. fs := TFileStream.Create(aFilename, fmOpenRead);
  1098. try
  1099. ReadFile(fs);
  1100. finally
  1101. FreeAndNil(fs);
  1102. end;
  1103. end;
  1104. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1105. procedure THeaderGenerator.ReadFile(const aStream: TStream);
  1106. type
  1107. TGenPass = (
  1108. gpConst,
  1109. gpType,
  1110. gpPointer,
  1111. gpVar,
  1112. gpImpl
  1113. );
  1114. var
  1115. xml: TDOMNode;
  1116. CurrentMark: Integer;
  1117. tpl: TStringList;
  1118. procedure AddObject(const aObj: TvkObject);
  1119. begin
  1120. if Assigned(aObj) then begin
  1121. fObjects.Add(aObj);
  1122. aObj.List := fObjects;
  1123. WriteLn(Format(' %-10s%s', [FormatType(aObj.VkType), aObj.Name]));
  1124. if (aObj.VkType = otConst) then
  1125. aObj.Mark := CurrentMark;
  1126. end;
  1127. end;
  1128. procedure ParseTypes(const xml: TDOMNode);
  1129. var
  1130. x: TDOMNode;
  1131. begin
  1132. x := xml.FirstChild;
  1133. while Assigned(x) do begin
  1134. AddObject(TvkObject.CreateFromXml(x));
  1135. x := x.NextSibling;
  1136. end;
  1137. end;
  1138. procedure GenerateType(const aCode: TStrings; const aType: TvkObjectType; const aPass: TGenPass);
  1139. var
  1140. o: TvkObject;
  1141. begin
  1142. for o in fObjects do begin
  1143. if (o.VkType = aType) and (o.Mark = CurrentMark) then begin
  1144. case aPass of
  1145. gpConst: o.GenerateConst(aCode);
  1146. gpType: o.GenerateType(aCode);
  1147. gpPointer: o.GeneratePtr(aCode);
  1148. gpVar: o.GenerateVar(aCode);
  1149. gpImpl: o.GenerateImpl(aCode);
  1150. end;
  1151. end;
  1152. end;
  1153. end;
  1154. procedure InsertAt(const aPlaceholder: String; const aText: TStrings);
  1155. var i, j: Integer;
  1156. begin
  1157. for i := tpl.Count-1 downto 0 do begin
  1158. if (Pos(aPlaceholder, tpl[i]) > 0) then begin
  1159. for j := aText.Count-1 downto 0 do
  1160. tpl.Insert(i, aText[j]);
  1161. end;
  1162. end;
  1163. end;
  1164. procedure InsertAt(const aPlaceholder: String; const aText: String);
  1165. var sl: TStringList;
  1166. begin
  1167. sl := TStringList.Create;
  1168. try
  1169. sl.Text := aText;
  1170. InsertAt(aPlaceholder, sl);
  1171. finally
  1172. FreeAndNil(sl);
  1173. end;
  1174. end;
  1175. procedure GeneratePass(const aType: TvkObjectType; const aPass: TGenPass; const aPrefix, aPlaceholder: String);
  1176. var sl: TStringList;
  1177. begin
  1178. sl := TStringList.Create;
  1179. try
  1180. GenerateType(sl, aType, aPass);
  1181. if (sl.Count > 0) then begin
  1182. sl.Insert(0, aPrefix);
  1183. sl.Add('');
  1184. end;
  1185. InsertAt(aPlaceholder, sl);
  1186. finally
  1187. FreeAndNil(sl);
  1188. end;
  1189. end;
  1190. procedure Generate(const aTypes: TvkObjectTypes);
  1191. var t: TvkObjectType;
  1192. begin
  1193. for t in aTypes do begin
  1194. GeneratePass(t, gpConst, Format('const { %ss }', [ LowerCase(FormatType(t)) ]), '{%INTERFACE%}');
  1195. GeneratePass(t, gpType, Format('type { %ss }', [ LowerCase(FormatType(t)) ]), '{%INTERFACE%}');
  1196. GeneratePass(t, gpPointer, Format('type { %s pointers }', [ LowerCase(FormatType(t)) ]), '{%INTERFACE%}');
  1197. GeneratePass(t, gpVar, Format('var { %s variables }', [ LowerCase(FormatType(t)) ]), '{%INTERFACE%}');
  1198. GeneratePass(t, gpImpl, '', '{%IMPLEMENTATION%}');
  1199. end;
  1200. end;
  1201. procedure Generate(const aName: DOMString);
  1202. begin
  1203. fObjects.Sort(@CompareVkObjDependency);
  1204. InsertAt('{%INTERFACE%}', Format('{********************************* %s *********************************}', [ aName ]));
  1205. InsertAt('{%IMPLEMENTATION%}', Format('{********************************* %s *********************************}', [ aName ]));
  1206. Generate([ otConst ]);
  1207. Generate([ otType, otHandle, otEnum, otStruct, otFuncPtr ]);
  1208. Generate([ otCommand ]);
  1209. inc(CurrentMark);
  1210. end;
  1211. procedure EnableFeature(const xml: TDOMNode);
  1212. var
  1213. x: TDOMNode;
  1214. begin
  1215. x := xml.FirstChild;
  1216. while Assigned(x) do begin
  1217. if (x.NodeName = 'require') then
  1218. EnableFeature(x)
  1219. else if (x.NodeName = 'type') then
  1220. fObjects.MarkObj(GetNodeAttrib(x, 'name'), VK_OBJECT_TYPES, CurrentMark)
  1221. else if (x.NodeName = 'command') then
  1222. fObjects.MarkObj(GetNodeAttrib(x, 'name'), [ otCommand ], CurrentMark);
  1223. x := x.NextSibling;
  1224. end;
  1225. if (xml.NodeName = 'feature') or (xml.NodeName = 'extension') then
  1226. Generate(GetNodeAttrib(xml, 'name'));
  1227. end;
  1228. procedure RemoveLines(const aText: TStrings);
  1229. var
  1230. i: Integer;
  1231. b: Boolean;
  1232. rx: TRegExpr;
  1233. begin
  1234. i := 0;
  1235. rx := TRegExpr.Create('{%.*?%}');
  1236. try
  1237. while (i < aText.Count) do begin
  1238. if (rx.Exec(aText[i])) then begin
  1239. aText.Delete(i);
  1240. continue;
  1241. end;
  1242. if (Trim(aText[i]) = '') then begin
  1243. if b then begin
  1244. aText.Delete(i);
  1245. continue;
  1246. end else
  1247. b := true;
  1248. end else
  1249. b := false;
  1250. inc(i);
  1251. end;
  1252. finally
  1253. FreeAndNil(rx);
  1254. end;
  1255. end;
  1256. begin
  1257. Clear;
  1258. ReadXMLFile(fDocument, aStream);
  1259. if not FileExists(TemplateFile) then
  1260. raise Exception.Create('file does not exist: ' + TemplateFile);
  1261. tpl := TStringList.Create;
  1262. try
  1263. tpl.LoadFromFile(TemplateFile);
  1264. CurrentMark := 1;
  1265. WriteLn('read xml data');
  1266. xml := fDocument.DocumentElement.FirstChild;
  1267. while Assigned(xml) do begin
  1268. if (xml.NodeName = 'types') or (xml.NodeName = 'commands') then
  1269. ParseTypes(xml)
  1270. else if (xml.NodeName = 'enums') then
  1271. AddObject(TvkTypeEnum.CreateFromXml(xml))
  1272. else if (xml.NodeName = 'comment') then
  1273. tpl.Text := Trim(COMMENT_HEAD + Trim(xml.TextContent) + COMMENT_BREAK + COMMENT_CONTENT + COMMENT_TAIL) + sLineBreak + tpl.Text
  1274. else if (xml.NodeName = 'feature') then
  1275. EnableFeature(xml);
  1276. xml := xml.NextSibling;
  1277. end;
  1278. RemoveLines(tpl);
  1279. tpl.SaveToFile(OutputFile);
  1280. finally
  1281. FreeAndNil(tpl);
  1282. end;
  1283. end;
  1284. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1285. procedure THeaderGenerator.Clear;
  1286. procedure CreateBaseType(const aName, aAlias, aParent: DOMString);
  1287. var t: TvkTypeSimple;
  1288. begin
  1289. t := TvkTypeSimple.Create(otType);
  1290. try
  1291. t.Name := aName;
  1292. t.Alias := aAlias;
  1293. t.Parent := aParent;
  1294. t.List := fObjects;
  1295. t.Mark := 1;
  1296. fObjects.Add(t);
  1297. except
  1298. FreeAndNil(t);
  1299. raise;
  1300. end;
  1301. end;
  1302. begin
  1303. fObjects.Clear;
  1304. CreateBaseType('PVkVoid', '', 'Pointer');
  1305. CreateBaseType('VkHandle', '', 'Pointer');
  1306. CreateBaseType('VkUint8', '', 'Byte');
  1307. CreateBaseType('VkUint16', '', 'Word');
  1308. CreateBaseType('VkUint32', '', 'Cardinal');
  1309. CreateBaseType('VkUint64', '', 'QWord');
  1310. CreateBaseType('VkInt16', '', 'SmallInt');
  1311. CreateBaseType('VkInt32', '', 'Integer');
  1312. CreateBaseType('VkInt64', '', 'Int64');
  1313. CreateBaseType('VkFloat', '', 'Single');
  1314. CreateBaseType('VkDouble', '', 'Double');
  1315. CreateBaseType('VkChar', '', 'AnsiChar');
  1316. CreateBaseType('VkSize', '', 'SizeUInt');
  1317. CreateBaseType('void', 'VkVoid', '');
  1318. CreateBaseType('uint8_t', 'VkUint8', '');
  1319. CreateBaseType('uint16_t', 'VkUint16', '');
  1320. CreateBaseType('uint32_t', 'VkUint32', '');
  1321. CreateBaseType('uint64_t', 'VkUint64', '');
  1322. CreateBaseType('int16_t', 'VkInt16', '');
  1323. CreateBaseType('int32_t', 'VkInt32', '');
  1324. CreateBaseType('int64_t', 'VkInt64', '');
  1325. CreateBaseType('float', 'VkFloat', '');
  1326. CreateBaseType('double', 'VkDouble', '');
  1327. CreateBaseType('char', 'VkChar', '');
  1328. CreateBaseType('size_t', 'VkSize', '');
  1329. end;
  1330. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1331. constructor THeaderGenerator.Create;
  1332. begin
  1333. inherited Create;
  1334. fObjects := TvkObjectList.Create;
  1335. end;
  1336. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1337. destructor THeaderGenerator.Destroy;
  1338. begin
  1339. FreeAndNil(fObjects);
  1340. FreeAndNil(fDocument);
  1341. inherited Destroy;
  1342. end;
  1343. end.