25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1544 lines
54 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 TryGetNodeValue(xml: TDOMNode; const aName: WideString; out aValue: DOMString): Boolean;
  301. var x: TDOMNode;
  302. begin
  303. x := xml.FindNode(aName);
  304. result := Assigned(x);
  305. if result then
  306. aValue := x.TextContent;
  307. end;
  308. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  309. function GetNodeValue(xml: TDOMNode; const aName: WideString; const aDefault: DOMString): DOMString;
  310. var x: TDOMNode;
  311. begin
  312. x := xml.FindNode(aName);
  313. if not Assigned(x)
  314. then result := aDefault
  315. else result := x.TextContent;
  316. end;
  317. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  318. function GetNodeAttrib(xml: TDOMNode; const aName: WideString): DOMString;
  319. var x: TDOMNode;
  320. begin
  321. if xml.HasAttributes then begin
  322. x := xml.Attributes.GetNamedItem(aName);
  323. if Assigned(x) then begin
  324. result := x.TextContent;
  325. exit;
  326. end;
  327. end;
  328. raise XmlException.Create(xml.NodeName + ' without ''' + aName + ''' attribute', xml);
  329. end;
  330. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  331. function GetNodeAttrib(xml: TDOMNode; const aName: WideString; const aDefault: DOMString): DOMString;
  332. var x: TDOMNode;
  333. begin
  334. result := aDefault;
  335. if xml.HasAttributes then begin
  336. x := xml.Attributes.GetNamedItem(aName);
  337. if Assigned(x) then
  338. result := x.TextContent;
  339. end;
  340. end;
  341. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  342. //XmlException//////////////////////////////////////////////////////////////////////////////////////////////////////////
  343. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  344. constructor XmlException.Create(const aMsg: WideString; const aXml: TDOMNode);
  345. begin
  346. inherited Create(String(aMsg + ': ' + aXml.TextContent));
  347. xml := aXml;
  348. end;
  349. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  350. //THeaderGenerator.TvkObjectList////////////////////////////////////////////////////////////////////////////////////////
  351. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  352. function THeaderGenerator.TvkObjectList.IndexOfObj(const aName: DOMstring; const aTypes: TvkObjectTypes): Integer;
  353. var o: TvkObject;
  354. begin
  355. if (aName = '') then
  356. raise Exception.Create('empty name');
  357. for result := 0 to Count-1 do begin
  358. o := Get(result);
  359. if (o.VkType in aTypes) and (o.Name = aName) then
  360. exit;
  361. end;
  362. result := -1;
  363. end;
  364. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  365. function THeaderGenerator.TvkObjectList.FindObj(const aName: DOMstring; const aTypes: TvkObjectTypes; out aObject): Boolean;
  366. var i: Integer;
  367. begin
  368. i := IndexOfObj(aName, aTypes);
  369. result := (i >= 0);
  370. if result
  371. then TvkObject(aObject) := Get(i)
  372. else TvkObject(aObject) := nil;
  373. end;
  374. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  375. procedure THeaderGenerator.TvkObjectList.MarkObj(const aName: DOMstring; const aTypes: TvkObjectTypes; const aMark: Integer);
  376. var o: TvkObject;
  377. begin
  378. if FindObj(aName, aTypes, o)
  379. then o.Mark := aMark
  380. else WriteResolveWarning(aName);
  381. end;
  382. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  383. function THeaderGenerator.TvkObjectList.GetPascalName(const aName: DOMString; const aPointer: Integer;
  384. const aArrSize: WideString): WideString;
  385. var o: TvkObject;
  386. begin
  387. if FindObj(aName, VK_OBJECT_TYPES, o)
  388. then result := o.GetPascalName(aPointer, aArrSize)
  389. else result := aName;
  390. end;
  391. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  392. //THeaderGenerator.TvkObject////////////////////////////////////////////////////////////////////////////////////////////
  393. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  394. procedure THeaderGenerator.TvkObject.SetMark(aValue: Integer);
  395. begin
  396. if (fMark <> 0) then
  397. exit;
  398. fMark := aValue;
  399. DoMark(fMark);
  400. end;
  401. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  402. function THeaderGenerator.TvkObject.GetDependencyOrder: Integer;
  403. begin
  404. result := 0;
  405. end;
  406. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  407. procedure THeaderGenerator.TvkObject.DoMark(const aMark: Integer);
  408. begin
  409. WriteLn(Format(' %-10s%-50s marked for generation', [FormatType(fType), fName]));
  410. end;
  411. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  412. procedure THeaderGenerator.TvkObject.GenPascalName(var aName: WideString; const aPointer: Integer; const aArrSize: WideString);
  413. var
  414. i: Integer;
  415. begin
  416. if (aName = '') then begin
  417. aName := fName;
  418. if (aName = 'void') then
  419. aName := 'VkVoid';
  420. for i := 0 to aPointer-1 do
  421. aName := 'P' + aName;
  422. end;
  423. if (aName = 'VkVoid') then
  424. raise Exception.Create('void can not be used as type');
  425. if (aArrSize <> '') then begin
  426. if TryStrToInt(String(aArrSize), i)
  427. then aName := WideString(Format('array[0..%d] of %s', [i, aName]))
  428. else aName := WideString(Format('array[0..%s-1] of %s', [aArrSize, aName]));
  429. end;
  430. end;
  431. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  432. procedure THeaderGenerator.TvkObject.AddCommentFromXml(xml: TDOMNode);
  433. begin
  434. xml := xml.FindNode('comment');
  435. if Assigned(xml) then
  436. fComment := xml.TextContent;
  437. end;
  438. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  439. function THeaderGenerator.TvkObject.GetPascalName(const aPointer: Integer; const aArrSize: WideString): WideString;
  440. begin
  441. result := '';
  442. GenPascalName(result, aPointer, aArrSize);
  443. end;
  444. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  445. function THeaderGenerator.TvkObject.GenerateConst(const aCode: TStrings): Boolean;
  446. begin
  447. result := not fConstGenerated;
  448. if not fConstGenerated then begin
  449. fConstGenerated := true;
  450. WriteLn(Format(' %-10s%-50s constants generated', [FormatType(fType), fName]));
  451. end;
  452. end;
  453. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  454. function THeaderGenerator.TvkObject.GenerateType(const aCode: TStrings): Boolean;
  455. begin
  456. result := not fTypeGenerated;
  457. if not fTypeGenerated then begin
  458. fTypeGenerated := true;
  459. WriteLn(Format(' %-10s%-50s type generated', [FormatType(fType), fName]));
  460. end;
  461. end;
  462. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  463. function THeaderGenerator.TvkObject.GeneratePtr(const aCode: TStrings): Boolean;
  464. begin
  465. result := not fPtrGenerated;
  466. if not fPtrGenerated then begin
  467. fPtrGenerated := true;
  468. WriteLn(Format(' %-10s%-50s pointer type generated', [FormatType(fType), fName]));
  469. end;
  470. end;
  471. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  472. function THeaderGenerator.TvkObject.GenerateVar(const aCode: TStrings): Boolean;
  473. begin
  474. result := not fVarGenerated;
  475. if not fVarGenerated then begin
  476. fVarGenerated := true;
  477. WriteLn(Format(' %-10s%-50s variables generated', [FormatType(fType), fName]));
  478. end;
  479. end;
  480. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  481. function THeaderGenerator.TvkObject.GenerateImpl(const aCode: TStrings): Boolean;
  482. begin
  483. result := not fImplGenerated;
  484. if not fImplGenerated then begin
  485. fImplGenerated := true;
  486. WriteLn(Format(' %-10s%-50s implementation generated', [FormatType(fType), fName]));
  487. end;
  488. end;
  489. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  490. constructor THeaderGenerator.TvkObject.Create(const aType: TvkObjectType);
  491. begin
  492. inherited Create;
  493. fType := aType;
  494. end;
  495. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  496. class function THeaderGenerator.TvkObject.CreateFromXml(const xml: TDOMNode): THeaderGenerator.TvkObject;
  497. var
  498. s, n: DOMString;
  499. x: TDOMNode;
  500. function GenerateVersionEnum: TvkTypeEnum;
  501. var
  502. rx: TRegExpr;
  503. v: TvkTypeEnum.TValue;
  504. begin
  505. result := TvkTypeEnum.Create(otConst);
  506. rx := TRegExpr.Create('\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)');
  507. try try
  508. if not rx.Exec(xml.TextContent) then
  509. raise XmlException.Create('VK_API_VERSION with malformed version', xml);
  510. v := TvkTypeEnum.TValue.Create;
  511. result.Values.Add(v);
  512. v.Name := 'VK_API_VERSION';
  513. v.Value := (StrToInt(rx.Match[1]) shl 22) or
  514. (StrToInt(rx.Match[2]) shl 12) or
  515. (StrToInt(rx.Match[3]) shl 0);
  516. v := TvkTypeEnum.TValue.Create;
  517. result.Values.Add(v);
  518. v.Name := 'VK_API_VERSION_MAJOR';
  519. v.Value := StrToInt(rx.Match[1]);
  520. v := TvkTypeEnum.TValue.Create;
  521. result.Values.Add(v);
  522. v.Name := 'VK_API_VERSION_MINOR';
  523. v.Value := StrToInt(rx.Match[2]);
  524. v := TvkTypeEnum.TValue.Create;
  525. result.Values.Add(v);
  526. v.Name := 'VK_API_VERSION_BUGFIX';
  527. v.Value := StrToInt(rx.Match[3]);
  528. finally
  529. FreeAndNil(rx);
  530. end;
  531. except
  532. FreeAndNil(result);
  533. raise;
  534. end;
  535. end;
  536. begin
  537. result := nil;
  538. if (xml.NodeName = 'type') and xml.HasAttributes then begin
  539. x := xml.Attributes.GetNamedItem('category');
  540. if not Assigned(x) then
  541. exit;
  542. s := x.TextContent;
  543. if (s = 'basetype') or (s = 'bitmask') then
  544. result := TvkTypeSimple.CreateFromXml(xml)
  545. else if (s = 'handle') then
  546. result := TvkTypeHandle.CreateFromXml(xml)
  547. else if (s = 'funcpointer') then
  548. result := TvkTypeFunctionPtr.CreateFromXml(xml)
  549. else if (s = 'struct') or (s = 'union') then
  550. result := TvkTypeStruct.CreateFromXml(xml)
  551. else if (s = 'define') and TryGetNodeValue(xml, 'name', n) and (n = 'VK_API_VERSION') then begin
  552. result := GenerateVersionEnum;
  553. end;
  554. end else if (xml.NodeName = 'command') then
  555. result := TvkCommand.CreateFromXml(xml);
  556. end;
  557. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  558. //THeaderGenerator.TvkTypeSimple////////////////////////////////////////////////////////////////////////////////////////
  559. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  560. function THeaderGenerator.TvkTypeSimple.GetDependencyOrder: Integer;
  561. begin
  562. result := inherited GetDependencyOrder;
  563. if Assigned(List) and (fParent <> '') then
  564. result := max(result, List.IndexOfObj(fParent, VK_OBJECT_TYPES) + 1);
  565. end;
  566. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  567. procedure THeaderGenerator.TvkTypeSimple.DoMark(const aMark: Integer);
  568. begin
  569. inherited DoMark(aMark);
  570. if (fParent <> '') and Assigned(fList) then
  571. fList.MarkObj(fParent, VK_OBJECT_TYPES, aMark);
  572. if (fAlias <> '') and Assigned(fList) then
  573. fList.MarkObj(fAlias, VK_OBJECT_TYPES, aMark);
  574. end;
  575. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  576. procedure THeaderGenerator.TvkTypeSimple.GenPascalName(var aName: WideString; const aPointer: Integer; const aArrSize: WideString);
  577. var i: Integer;
  578. begin
  579. if (fAlias <> '')
  580. then aName := fAlias
  581. else aName := fName;
  582. if (aName = 'void') then
  583. aName := 'VkVoid';
  584. for i := 0 to aPointer-1 do
  585. aName := 'P' + aName;
  586. inherited GenPascalName(aName, aPointer, aArrSize);
  587. end;
  588. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  589. function THeaderGenerator.TvkTypeSimple.GenerateType(const aCode: TStrings): Boolean;
  590. begin
  591. result := inherited GenerateType(aCode);
  592. if result and (fParent <> '') and Assigned(List) then
  593. aCode.Add(Format(' %-62s = %s;', [ fName, List.GetPascalName(fParent, 0) ]));
  594. end;
  595. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  596. function THeaderGenerator.TvkTypeSimple.GeneratePtr(const aCode: TStrings): Boolean;
  597. begin
  598. result := inherited GeneratePtr(aCode);
  599. if result and (fParent <> '') and Assigned(List) then begin
  600. aCode.Add(Format(' P%-61s = ^%0:s;', [ fName ]));
  601. aCode.Add(Format(' PP%-60s = ^P%0:s;', [ fName ]));
  602. end;
  603. end;
  604. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  605. class function THeaderGenerator.TvkTypeSimple.CreateFromXml(const xml: TDOMNode): THeaderGenerator.TvkTypeSimple;
  606. begin
  607. result := TvkTypeSimple.Create(otType);
  608. try
  609. result.Name := GetNodeValue(xml, 'name');
  610. result.Parent := GetNodeValue(xml, 'type');
  611. except
  612. FreeAndNil(result);
  613. raise;
  614. end;
  615. end;
  616. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  617. //THeaderGenerator.TvkTypeHandle////////////////////////////////////////////////////////////////////////////////////////
  618. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  619. class function THeaderGenerator.TvkTypeHandle.CreateFromXml(const xml: TDOMNode): THeaderGenerator.TvkTypeHandle;
  620. begin
  621. result := TvkTypeHandle.Create(otHandle);
  622. try
  623. result.Name := GetNodeValue(xml, 'name');
  624. result.Parent := GetNodeValue(xml, 'parent', 'VkHandle');
  625. result.NonDispatchable := (GetNodeValue(xml, 'type', '') = 'VK_DEFINE_NON_DISPATCHABLE_HANDLE');
  626. except
  627. FreeAndNil(result);
  628. raise;
  629. end;
  630. end;
  631. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  632. function THeaderGenerator.TvkTypeFunction.GetDependencyOrder: Integer;
  633. var a: TArgument;
  634. begin
  635. result := inherited GetDependencyOrder;
  636. if not Assigned(List) then
  637. exit;
  638. for a in fArguments do
  639. result := max(result, List.IndexOfObj(a.Typ, VK_OBJECT_TYPES));
  640. end;
  641. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  642. procedure THeaderGenerator.TvkTypeFunction.DoMark(const aMark: Integer);
  643. var a: TArgument;
  644. begin
  645. inherited DoMark(aMark);
  646. if Assigned(fList) then begin
  647. fList.MarkObj(fReturnValue.Typ, VK_OBJECT_TYPES, aMark);
  648. for a in fArguments do
  649. fList.MarkObj(a.Typ, VK_OBJECT_TYPES, aMark);
  650. end;
  651. end;
  652. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  653. procedure THeaderGenerator.TvkTypeFunction.GenPascalName(var aName: WideString; const aPointer: Integer;
  654. const aArrSize: WideString);
  655. var rx: TRegExpr;
  656. begin
  657. if (aPointer > 0) then
  658. Exception.Create('function pointer can not be used as pointer type');
  659. if (aArrSize <> '') then
  660. Exception.Create('function pointer can not be used as array type');
  661. rx := TRegExpr.Create('PFN_([-_A-Za-z0-9]+)');
  662. try
  663. if rx.Exec(String(fName))
  664. then aName := 'T' + WideString(rx.Match[1])
  665. else aName := 'T' + fName;
  666. finally
  667. FreeAndNil(rx);
  668. end;
  669. end;
  670. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  671. procedure THeaderGenerator.TvkTypeFunction.GenerateFunctionPtr(const aCode: TStrings);
  672. var
  673. s: WideString;
  674. i: Integer;
  675. a: TArgument;
  676. begin
  677. s := WideString(Format(' %-50s', [ GetPascalName(0, '') ]));
  678. if (ReturnValue.Typ = 'void') and (ReturnValue.IsPointer = 0)
  679. then s := s + ' = procedure('
  680. else s := s + ' = function (';
  681. for i := 0 to fArguments.Count-1 do begin
  682. a := fArguments[i];
  683. if a.IsConst then
  684. s := s + 'const ';
  685. s := s + PrepareName(a.Name, a.Typ) + ': ' + List.GetPascalName(a.Typ, a.IsPointer);
  686. if (i < fArguments.Count-1) then
  687. s := s + '; ';
  688. end;
  689. s := s + ')';
  690. if (ReturnValue.Typ <> 'void') or (ReturnValue.IsPointer > 0) then
  691. s := s + ': ' + List.GetPascalName(ReturnValue.Typ, ReturnValue.IsPointer);
  692. s := s + '; {$IFDEF VK_CDECL}cdecl{$ELSE}stdcall{$ENDIF};';
  693. aCode.Add(String(s));
  694. end;
  695. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  696. constructor THeaderGenerator.TvkTypeFunction.Create(const aType: TvkObjectType);
  697. begin
  698. inherited Create(aType);
  699. fReturnValue := TArgument.Create;
  700. fArguments := TArgumentList.Create;
  701. end;
  702. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  703. destructor THeaderGenerator.TvkTypeFunction.Destroy;
  704. begin
  705. FreeAndNil(fReturnValue);
  706. FreeAndNil(fArguments);
  707. inherited Destroy;
  708. end;
  709. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  710. //THeaderGenerator.TvkTypeFunctionPtr///////////////////////////////////////////////////////////////////////////////////
  711. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  712. function THeaderGenerator.TvkTypeFunctionPtr.GenerateType(const aCode: TStrings): Boolean;
  713. begin
  714. result := inherited GenerateType(aCode);
  715. if result and Assigned(List) then
  716. GenerateFunctionPtr(aCode);
  717. end;
  718. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  719. class function THeaderGenerator.TvkTypeFunctionPtr.CreateFromXml(const xml: TDOMNode): THeaderGenerator.TvkTypeFunctionPtr;
  720. var
  721. x, p: TDOMNode;
  722. a: TArgument;
  723. rx: TRegExpr;
  724. begin
  725. result := TvkTypeFunctionPtr.Create(otFuncPtr);
  726. try
  727. x := xml.FindNode('name');
  728. if not Assigned(x) then
  729. raise XmlException.Create(xml.NodeName + ' witout child ''name''', xml);
  730. result.Name := x.TextContent;
  731. p := x.PreviousSibling;
  732. if not Assigned(p) then
  733. raise XmlException.Create(xml.NodeName + ' witout return type', xml);
  734. rx := TRegExpr.Create('typedef\s+((const)?)\s*([-_A-Za-z0-9\s]+?)\s*((\*\s*(const)?\s*)*)\s*\(');
  735. try
  736. if not rx.Exec(String(p.TextContent)) then
  737. raise XmlException.Create('unable to parse return type of function pointer', xml);
  738. result.ReturnValue.IsConst := (Trim(rx.Match[1]) = 'const');
  739. result.ReturnValue.Typ := WideString(Trim(rx.Match[3]));
  740. result.ReturnValue.IsPointer := PointerCount(Trim(rx.Match[4]));
  741. x := xml.FirstChild;
  742. while Assigned(x) do begin
  743. if (x.NodeName = 'type') then begin
  744. a := TArgument.Create;
  745. try
  746. p := x.PreviousSibling;
  747. if not Assigned(p) then
  748. raise XmlException.Create('unable to parse function pointer arguments', xml);
  749. rx.Expression := '[A-Za-z]*';
  750. a.IsConst := rx.Exec(String(p.TextContent)) and (rx.Match[0] = 'const');
  751. a.Typ := x.TextContent;
  752. p := x.NextSibling;
  753. if not Assigned(p) then
  754. raise XmlException.Create('unable to parse function pointer arguments', xml);
  755. rx.Expression := '((\*\s*(const)?\s*)*)\s*([-_A-Za-z0-9]+)';
  756. if not rx.Exec(String(p.TextContent)) then
  757. raise XmlException.Create('unable to parse function pointer arguments', xml);
  758. a.IsPointer := PointerCount((rx.Match[1]));
  759. a.Name := WideString(Trim(rx.Match[4]));
  760. result.Arguments.Add(a);
  761. except
  762. FreeAndNil(a)
  763. end;
  764. end;
  765. x := x.NextSibling;
  766. end;
  767. finally
  768. FreeAndNil(rx);
  769. end;
  770. except
  771. FreeAndNil(result);
  772. raise;
  773. end;
  774. end;
  775. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  776. //THeaderGenerator.TvkCommand///////////////////////////////////////////////////////////////////////////////////////
  777. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  778. function THeaderGenerator.TvkCommand.GenerateType(const aCode: TStrings): Boolean;
  779. begin
  780. result := inherited GenerateType(aCode);
  781. if result and Assigned(List) then
  782. GenerateFunctionPtr(aCode);
  783. end;
  784. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  785. function THeaderGenerator.TvkCommand.GenerateVar(const aCode: TStrings): Boolean;
  786. begin
  787. result := inherited GenerateVar(aCode);
  788. if result then
  789. aCode.Add(Format(' %-50s %s = nil;', [ fName + ':', GetPascalName(0, '') ]));
  790. end;
  791. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  792. function THeaderGenerator.TvkCommand.GenerateImpl(const aCode: TStrings): Boolean;
  793. begin
  794. result := inherited GenerateImpl(aCode);
  795. if result then
  796. aCode.Add(Format(' %-50s := vkGetProcAddress(''%0:s'');', [ fName ]));
  797. end;
  798. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  799. class function THeaderGenerator.TvkCommand.CreateFromXml(const xml: TDOMNode): THeaderGenerator.TvkCommand;
  800. procedure ParseProto(const x: TDOMNode);
  801. begin
  802. result.Name := GetNodeValue(x, 'name');
  803. result.ReturnValue.Typ := GetNodeValue(x, 'type');
  804. end;
  805. procedure ParseParam(const x: TDOMNode);
  806. var
  807. p: TDOMNode;
  808. a: TArgument;
  809. rx: TRegExpr;
  810. begin
  811. a := TArgument.Create;
  812. rx := TRegExpr.Create;
  813. try try
  814. p := x.FindNode('name');
  815. if not Assigned(p) then
  816. raise XmlException.Create('unable to parse command; param without name', xml);
  817. a.Name := p.TextContent;
  818. p := x.FindNode('type');
  819. if not Assigned(p) then
  820. raise XmlException.Create('unable to parse command; param without type', xml);
  821. a.Typ := p.TextContent;
  822. a.IsConst := Assigned(p.PreviousSibling) and (Trim(p.PreviousSibling.TextContent) = 'const');
  823. rx.Expression := '((\*\s*(const)?\s*)*)';
  824. if Assigned(p.NextSibling) and rx.Exec(String(p.NextSibling.TextContent)) then
  825. a.IsPointer := PointerCount(rx.Match[0]);
  826. result.Arguments.Add(a);
  827. finally
  828. FreeAndNil(rx);
  829. end;
  830. except
  831. FreeAndNil(a);
  832. raise;
  833. end;
  834. end;
  835. var
  836. x: TDOMNode;
  837. begin
  838. result := TvkCommand.Create(otCommand);
  839. try
  840. x := xml.FirstChild;
  841. while Assigned(x) do begin
  842. if (x.NodeName = 'proto') then
  843. ParseProto(x)
  844. else if (x.NodeName = 'param') then
  845. ParseParam(x);
  846. x := x.NextSibling;
  847. end;
  848. except
  849. FreeAndNil(result);
  850. raise;
  851. end;
  852. end;
  853. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  854. //THeaderGenerator.TvkTypeStruct////////////////////////////////////////////////////////////////////////////////////////
  855. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  856. function THeaderGenerator.TvkTypeStruct.GetDependencyOrder: Integer;
  857. var
  858. m: TMember;
  859. begin
  860. result := inherited GetDependencyOrder;
  861. if not Assigned(List) then
  862. exit;
  863. for m in fMember do
  864. result := max(result, List.IndexOfObj(m.Typ, VK_OBJECT_TYPES) + 1);
  865. end;
  866. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  867. procedure THeaderGenerator.TvkTypeStruct.DoMark(const aMark: Integer);
  868. var m: TMember;
  869. begin
  870. inherited DoMark(aMark);
  871. if Assigned(fList) then begin
  872. for m in fMember do
  873. fList.MarkObj(m.Typ, VK_OBJECT_TYPES, aMark);
  874. end;
  875. end;
  876. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  877. procedure THeaderGenerator.TvkTypeStruct.GenPascalName(var aName: WideString; const aPointer: Integer; const aArrSize: WideString);
  878. var i: Integer;
  879. begin
  880. if (aPointer > 0) then begin
  881. aName := fName;
  882. for i := 0 to aPointer-1 do
  883. aName := 'P' + aName;
  884. end else
  885. aName := 'T' + fName;
  886. inherited GenPascalName(aName, aPointer, aArrSize);
  887. end;
  888. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  889. function THeaderGenerator.TvkTypeStruct.GenerateType(const aCode: TStrings): Boolean;
  890. var
  891. prefix, postfix: String;
  892. i, indent: Integer;
  893. m: TMember;
  894. begin
  895. result := inherited GenerateType(aCode);
  896. result := inherited GeneratePtr(aCode) or result;
  897. if result and Assigned(List) then begin
  898. postfix := ';';
  899. indent := 50;
  900. aCode.Add(' T%s = record', [ fName ]);
  901. if IsUnion then begin
  902. aCode.Add(' case Integer of');
  903. postfix := ');';
  904. indent := 42;
  905. end;
  906. for i := 0 to fMember.Count-1 do begin
  907. m := fMember[i];
  908. if IsUnion
  909. then prefix := Format(' %.3d: (', [ i ])
  910. else prefix := ' ';
  911. aCode.Add(Format('%s%-*s%s%s', [ prefix, indent, PrepareName(m.Name, m.Typ) + ': ', List.GetPascalName(m.Typ, m.IsPointer, m.ArrSize), postfix ]));
  912. end;
  913. aCode.Add(' end;');
  914. aCode.Add(' P%s = ^T%0:s;', [ fName ]);
  915. aCode.Add(' PP%s = ^P%0:s;', [ fName ]);
  916. aCode.Add('');
  917. end;
  918. end;
  919. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  920. //THeaderGenerator.TvkTypeStruct////////////////////////////////////////////////////////////////////////////////////////
  921. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  922. constructor THeaderGenerator.TvkTypeStruct.Create(const aType: TvkObjectType);
  923. begin
  924. inherited Create(aType);
  925. fMember := TMemberList.Create;
  926. end;
  927. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  928. destructor THeaderGenerator.TvkTypeStruct.Destroy;
  929. begin
  930. FreeAndNil(fMember);
  931. inherited Destroy;
  932. end;
  933. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  934. class function THeaderGenerator.TvkTypeStruct.CreateFromXml(const xml: TDOMNode): THeaderGenerator.TvkTypeStruct;
  935. var
  936. x, p: TDOMNode;
  937. m: TMember;
  938. rx: TRegExpr;
  939. begin
  940. result := TvkTypeStruct.Create(otStruct);
  941. try
  942. result.Name := GetNodeAttrib(xml, 'name');
  943. result.IsUnion := (GetNodeAttrib(xml, 'category') = 'union');
  944. x := xml.FirstChild;
  945. while Assigned(x) do begin
  946. if (x.NodeName = 'member') then begin
  947. m := TMember.Create;
  948. rx := TRegExpr.Create('');
  949. try try
  950. // read name
  951. p := x.FindNode('name');
  952. if not Assigned(p) then
  953. raise XmlException.Create('struct member without name', xml);
  954. m.Name := p.TextContent;
  955. p := p.NextSibling;
  956. while Assigned(p) do begin
  957. m.Name := m.Name + p.TextContent;
  958. p := p.NextSibling;
  959. end;
  960. m.Name := Trim(m.Name);
  961. rx.Expression := '([-_A-Za-z0-9]+)\s*\[\s*([-_A-Za-z0-9]+)\s*\]';
  962. if rx.Exec(String(m.Name)) then begin
  963. m.Name := WideString(rx.Match[1]);
  964. m.ArrSize := WideString(rx.Match[2]);
  965. end;
  966. // read type
  967. p := x.FindNode('type');
  968. if not Assigned(p) then
  969. raise XmlException.Create('struct member without type', xml);
  970. m.Typ := p.TextContent;
  971. m.IsConst := Assigned(p.PreviousSibling) and (Trim(p.PreviousSibling.TextContent) = 'const');
  972. rx.Expression := '((\*\s*(const)?\s*)*)';
  973. if Assigned(p.NextSibling) and rx.Exec(String(p.NextSibling.TextContent)) then
  974. m.IsPointer := PointerCount(rx.Match[0]);
  975. result.Member.Add(m);
  976. finally
  977. FreeAndNil(rx);
  978. end;
  979. except
  980. FreeAndNil(m);
  981. end;
  982. end;
  983. x := x.NextSibling;
  984. end;
  985. except
  986. FreeAndNil(result);
  987. raise;
  988. end;
  989. end;
  990. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  991. //THeaderGenerator.TvkTypeEnum//////////////////////////////////////////////////////////////////////////////////////////
  992. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  993. procedure THeaderGenerator.TvkTypeEnum.GenPascalName(var aName: WideString; const aPointer: Integer; const aArrSize: WideString);
  994. var i: Integer;
  995. begin
  996. if (fName = '') then
  997. raise Exception.Create('enum with empty name');
  998. if (aPointer > 0) then begin
  999. aName := fName;
  1000. for i := 0 to aPointer-1 do
  1001. aName := 'P' + aName;
  1002. end else
  1003. aName := 'T' + fName;
  1004. inherited GenPascalName(aName, aPointer, aArrSize);
  1005. end;
  1006. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1007. function THeaderGenerator.TvkTypeEnum.GenerateConst(const aCode: TStrings): Boolean;
  1008. var
  1009. value: String;
  1010. i: Integer;
  1011. v: TValue;
  1012. begin
  1013. result := inherited GenerateConst(aCode);
  1014. if result and (VkType = otConst) then begin
  1015. for i := 0 to fValues.Count-1 do begin
  1016. v := fValues[i];
  1017. if v.IsBit
  1018. then value := Format('(1 shl %s)', [ IntToStr(v.Value) ])
  1019. else value := v.Value;
  1020. aCode.Add(Format(' %-62s = %s;', [ v.Name, value ]));
  1021. end;
  1022. aCode.Add('');
  1023. end;
  1024. end;
  1025. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1026. function THeaderGenerator.TvkTypeEnum.GenerateType(const aCode: TStrings): Boolean;
  1027. var
  1028. value: String;
  1029. i: Integer;
  1030. v: TValue;
  1031. begin
  1032. result := inherited GenerateType(aCode);
  1033. if result and (VkType = otEnum) then begin
  1034. aCode.Add(Format(' T%s = (', [ fName ]));
  1035. for i := 0 to fValues.Count-1 do begin
  1036. v := fValues[i];
  1037. if v.IsBit
  1038. then value := Format('(1 shl %s)', [ IntToStr(v.Value) ])
  1039. else value := v.Value;
  1040. aCode.Add(Format(' %-60s = %s', [ v.Name, value ]));
  1041. if (i < fValues.Count-1) then
  1042. aCode[aCode.Count-1] := aCode[aCode.Count-1] + ',';
  1043. end;
  1044. aCode.Add(' );');
  1045. aCode.Add(Format(' P%s = ^T%0:s;', [ fName ]));
  1046. aCode.Add('');
  1047. end;
  1048. end;
  1049. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1050. constructor THeaderGenerator.TvkTypeEnum.Create(const aType: TvkObjectType);
  1051. begin
  1052. inherited Create(aType);
  1053. fValues := TValueList.Create;
  1054. end;
  1055. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1056. destructor THeaderGenerator.TvkTypeEnum.Destroy;
  1057. begin
  1058. FreeAndNil(fValues);
  1059. inherited Destroy;
  1060. end;
  1061. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1062. class function THeaderGenerator.TvkTypeEnum.CreateFromXml(const xml: TDOMNode): THeaderGenerator.TvkTypeEnum;
  1063. var
  1064. x, p: TDOMNode;
  1065. v: TValue;
  1066. function StrToValue(s: String): Variant;
  1067. var
  1068. f: TFormatSettings;
  1069. rx: TRegExpr;
  1070. begin
  1071. f.DecimalSeparator := '.';
  1072. rx := TRegExpr.Create;
  1073. try
  1074. result := Unassigned;
  1075. rx.Expression := '^-?([0-9]+)$';
  1076. if rx.Exec(s) then
  1077. result := StrToInt(rx.Match[0]);
  1078. rx.Expression := '^0x([0-9A-Fa-f]+)$';
  1079. if rx.Exec(s) then
  1080. result := '$' + rx.Match[1];
  1081. rx.Expression := '^([0-9\.]+)(f|d)?$';
  1082. if rx.Exec(s) then begin
  1083. result := StrToFloat(rx.Match[1], f);
  1084. if (rx.Match[2] = 'd') then
  1085. result := Double(result);
  1086. end;
  1087. rx.Expression := '^\(~0U([L]*)\)$';
  1088. if rx.Exec(s) then begin
  1089. if (rx.Match[2] = '')
  1090. then result := '$' + IntToHex(High(UInt32), 2 * sizeof(UInt32))
  1091. else result := '$' + IntToHex(High(UInt64), 2 * sizeof(UInt64));
  1092. end;
  1093. if (result = Unassigned) then
  1094. raise XmlException.Create(WideString('invalid enum value (' + s + ')'), xml);
  1095. finally
  1096. FreeAndNil(rx);
  1097. end;
  1098. end;
  1099. begin
  1100. x := xml.Attributes.GetNamedItem('type');
  1101. if Assigned(x)
  1102. then result := TvkTypeEnum.Create(otEnum)
  1103. else result := TvkTypeEnum.Create(otConst);
  1104. try
  1105. result.Name := GetNodeAttrib(xml, 'name');
  1106. x := xml.FirstChild;
  1107. while Assigned(x) do begin
  1108. if (x.NodeName = 'enum') then begin
  1109. v := TValue.Create;
  1110. try
  1111. v.Name := GetNodeAttrib(x, 'name');
  1112. p := x.Attributes.GetNamedItem('value');
  1113. if Assigned(p) then begin
  1114. v.IsBit := false;
  1115. v.Value := StrToValue(String(p.TextContent));
  1116. end else begin
  1117. p := x.Attributes.GetNamedItem('bitpos');
  1118. if not Assigned(p) then
  1119. raise XmlException.Create('enum without value or bitpos', xml);
  1120. v.IsBit := true;
  1121. v.Value := StrToValue(String(p.TextContent));
  1122. end;
  1123. result.Values.Add(v);
  1124. except
  1125. FreeAndNil(v);
  1126. raise;
  1127. end;
  1128. end;
  1129. x := x.NextSibling;
  1130. end;
  1131. except
  1132. FreeAndNil(result);
  1133. raise;
  1134. end;
  1135. end;
  1136. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1137. //THeaderGenerator//////////////////////////////////////////////////////////////////////////////////////////////////////
  1138. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1139. procedure THeaderGenerator.ReadFile(const aFilename: String);
  1140. var
  1141. fs: TFileStream;
  1142. begin
  1143. if not FileExists(aFilename) then
  1144. raise Exception.Create('file does not exist: ' + aFilename);
  1145. fs := TFileStream.Create(aFilename, fmOpenRead);
  1146. try
  1147. ReadFile(fs);
  1148. finally
  1149. FreeAndNil(fs);
  1150. end;
  1151. end;
  1152. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1153. procedure THeaderGenerator.ReadFile(const aStream: TStream);
  1154. type
  1155. TGenPass = (
  1156. gpConst,
  1157. gpType,
  1158. gpPointer,
  1159. gpVar,
  1160. gpImpl
  1161. );
  1162. var
  1163. xml: TDOMNode;
  1164. CurrentMark: Integer;
  1165. tpl: TStringList;
  1166. procedure AddObject(const aObj: TvkObject);
  1167. begin
  1168. if Assigned(aObj) then begin
  1169. fObjects.Add(aObj);
  1170. aObj.List := fObjects;
  1171. WriteLn(Format(' %-10s%s', [FormatType(aObj.VkType), aObj.Name]));
  1172. if (aObj.VkType = otConst) then
  1173. aObj.Mark := CurrentMark;
  1174. end;
  1175. end;
  1176. procedure ParseTypes(const xml: TDOMNode);
  1177. var
  1178. x: TDOMNode;
  1179. begin
  1180. x := xml.FirstChild;
  1181. while Assigned(x) do begin
  1182. AddObject(TvkObject.CreateFromXml(x));
  1183. x := x.NextSibling;
  1184. end;
  1185. end;
  1186. procedure GenerateType(const aCode: TStrings; const aType: TvkObjectType; const aPass: TGenPass);
  1187. var
  1188. o: TvkObject;
  1189. begin
  1190. for o in fObjects do begin
  1191. if (o.VkType = aType) and (o.Mark = CurrentMark) then begin
  1192. case aPass of
  1193. gpConst: o.GenerateConst(aCode);
  1194. gpType: o.GenerateType(aCode);
  1195. gpPointer: o.GeneratePtr(aCode);
  1196. gpVar: o.GenerateVar(aCode);
  1197. gpImpl: o.GenerateImpl(aCode);
  1198. end;
  1199. end;
  1200. end;
  1201. end;
  1202. procedure InsertAt(const aPlaceholder: String; const aText: TStrings);
  1203. var i, j: Integer;
  1204. begin
  1205. for i := tpl.Count-1 downto 0 do begin
  1206. if (Pos(aPlaceholder, tpl[i]) > 0) then begin
  1207. for j := aText.Count-1 downto 0 do
  1208. tpl.Insert(i, aText[j]);
  1209. end;
  1210. end;
  1211. end;
  1212. procedure InsertAt(const aPlaceholder: String; const aText: String);
  1213. var sl: TStringList;
  1214. begin
  1215. sl := TStringList.Create;
  1216. try
  1217. sl.Text := aText;
  1218. InsertAt(aPlaceholder, sl);
  1219. finally
  1220. FreeAndNil(sl);
  1221. end;
  1222. end;
  1223. procedure GeneratePass(const aType: TvkObjectType; const aPass: TGenPass; const aPrefix, aPlaceholder: String);
  1224. var sl: TStringList;
  1225. begin
  1226. sl := TStringList.Create;
  1227. try
  1228. GenerateType(sl, aType, aPass);
  1229. if (sl.Count > 0) then begin
  1230. sl.Insert(0, aPrefix);
  1231. sl.Add('');
  1232. end;
  1233. InsertAt(aPlaceholder, sl);
  1234. finally
  1235. FreeAndNil(sl);
  1236. end;
  1237. end;
  1238. procedure Generate(const aTypes: TvkObjectTypes);
  1239. var t: TvkObjectType;
  1240. begin
  1241. for t in aTypes do begin
  1242. GeneratePass(t, gpConst, Format('const { %ss }', [ LowerCase(FormatType(t)) ]), '{%INTERFACE%}');
  1243. GeneratePass(t, gpType, Format('type { %ss }', [ LowerCase(FormatType(t)) ]), '{%INTERFACE%}');
  1244. GeneratePass(t, gpPointer, Format('type { %s pointers }', [ LowerCase(FormatType(t)) ]), '{%INTERFACE%}');
  1245. GeneratePass(t, gpVar, Format('var { %s variables }', [ LowerCase(FormatType(t)) ]), '{%INTERFACE%}');
  1246. GeneratePass(t, gpImpl, '', '{%IMPLEMENTATION%}');
  1247. end;
  1248. end;
  1249. procedure Generate(const aName: DOMString);
  1250. begin
  1251. fObjects.Sort(@CompareVkObjDependency);
  1252. InsertAt('{%INTERFACE%}', Format('{********************************* %s *********************************}', [ aName ]));
  1253. InsertAt('{%IMPLEMENTATION%}', Format('{********************************* %s *********************************}', [ aName ]));
  1254. Generate([ otConst ]);
  1255. Generate([ otType, otHandle, otEnum, otStruct, otFuncPtr ]);
  1256. Generate([ otCommand ]);
  1257. inc(CurrentMark);
  1258. end;
  1259. procedure EnableFeature(const xml: TDOMNode);
  1260. var
  1261. x: TDOMNode;
  1262. begin
  1263. x := xml.FirstChild;
  1264. while Assigned(x) do begin
  1265. if (x.NodeName = 'require') then
  1266. EnableFeature(x)
  1267. else if (x.NodeName = 'type') then
  1268. fObjects.MarkObj(GetNodeAttrib(x, 'name'), VK_OBJECT_TYPES, CurrentMark)
  1269. else if (x.NodeName = 'command') then
  1270. fObjects.MarkObj(GetNodeAttrib(x, 'name'), [ otCommand ], CurrentMark);
  1271. x := x.NextSibling;
  1272. end;
  1273. if (xml.NodeName = 'feature') or (xml.NodeName = 'extension') then
  1274. Generate(GetNodeAttrib(xml, 'name'));
  1275. end;
  1276. procedure RemoveLines(const aText: TStrings);
  1277. var
  1278. i: Integer;
  1279. b: Boolean;
  1280. rx: TRegExpr;
  1281. begin
  1282. i := 0;
  1283. rx := TRegExpr.Create('{%.*?%}');
  1284. try
  1285. while (i < aText.Count) do begin
  1286. if (rx.Exec(aText[i])) then begin
  1287. aText.Delete(i);
  1288. continue;
  1289. end;
  1290. if (Trim(aText[i]) = '') then begin
  1291. if b then begin
  1292. aText.Delete(i);
  1293. continue;
  1294. end else
  1295. b := true;
  1296. end else
  1297. b := false;
  1298. inc(i);
  1299. end;
  1300. finally
  1301. FreeAndNil(rx);
  1302. end;
  1303. end;
  1304. begin
  1305. Clear;
  1306. ReadXMLFile(fDocument, aStream);
  1307. if not FileExists(TemplateFile) then
  1308. raise Exception.Create('file does not exist: ' + TemplateFile);
  1309. tpl := TStringList.Create;
  1310. try
  1311. tpl.LoadFromFile(TemplateFile);
  1312. CurrentMark := 1;
  1313. WriteLn('read xml data');
  1314. xml := fDocument.DocumentElement.FirstChild;
  1315. while Assigned(xml) do begin
  1316. if (xml.NodeName = 'types') or (xml.NodeName = 'commands') then
  1317. ParseTypes(xml)
  1318. else if (xml.NodeName = 'enums') then
  1319. AddObject(TvkTypeEnum.CreateFromXml(xml))
  1320. else if (xml.NodeName = 'comment') then
  1321. tpl.Text := Trim(COMMENT_HEAD + Trim(xml.TextContent) + COMMENT_BREAK + COMMENT_CONTENT + COMMENT_TAIL) + sLineBreak + tpl.Text
  1322. else if (xml.NodeName = 'feature') then
  1323. EnableFeature(xml);
  1324. xml := xml.NextSibling;
  1325. end;
  1326. RemoveLines(tpl);
  1327. tpl.SaveToFile(OutputFile);
  1328. finally
  1329. FreeAndNil(tpl);
  1330. end;
  1331. end;
  1332. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1333. procedure THeaderGenerator.Clear;
  1334. procedure CreateBaseType(const aName, aAlias, aParent: DOMString);
  1335. var t: TvkTypeSimple;
  1336. begin
  1337. t := TvkTypeSimple.Create(otType);
  1338. try
  1339. t.Name := aName;
  1340. t.Alias := aAlias;
  1341. t.Parent := aParent;
  1342. t.List := fObjects;
  1343. t.Mark := 1;
  1344. fObjects.Add(t);
  1345. except
  1346. FreeAndNil(t);
  1347. raise;
  1348. end;
  1349. end;
  1350. begin
  1351. fObjects.Clear;
  1352. CreateBaseType('PVkVoid', '', 'Pointer');
  1353. CreateBaseType('VkHandle', '', 'Pointer');
  1354. CreateBaseType('VkUint8', '', 'Byte');
  1355. CreateBaseType('VkUint16', '', 'Word');
  1356. CreateBaseType('VkUint32', '', 'Cardinal');
  1357. CreateBaseType('VkUint64', '', 'QWord');
  1358. CreateBaseType('VkInt16', '', 'SmallInt');
  1359. CreateBaseType('VkInt32', '', 'Integer');
  1360. CreateBaseType('VkInt64', '', 'Int64');
  1361. CreateBaseType('VkFloat', '', 'Single');
  1362. CreateBaseType('VkDouble', '', 'Double');
  1363. CreateBaseType('VkChar', '', 'AnsiChar');
  1364. CreateBaseType('VkSize', '', 'SizeUInt');
  1365. CreateBaseType('void', 'VkVoid', '');
  1366. CreateBaseType('uint8_t', 'VkUint8', '');
  1367. CreateBaseType('uint16_t', 'VkUint16', '');
  1368. CreateBaseType('uint32_t', 'VkUint32', '');
  1369. CreateBaseType('uint64_t', 'VkUint64', '');
  1370. CreateBaseType('int16_t', 'VkInt16', '');
  1371. CreateBaseType('int32_t', 'VkInt32', '');
  1372. CreateBaseType('int64_t', 'VkInt64', '');
  1373. CreateBaseType('float', 'VkFloat', '');
  1374. CreateBaseType('double', 'VkDouble', '');
  1375. CreateBaseType('char', 'VkChar', '');
  1376. CreateBaseType('size_t', 'VkSize', '');
  1377. end;
  1378. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1379. constructor THeaderGenerator.Create;
  1380. begin
  1381. inherited Create;
  1382. fObjects := TvkObjectList.Create;
  1383. end;
  1384. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1385. destructor THeaderGenerator.Destroy;
  1386. begin
  1387. FreeAndNil(fObjects);
  1388. FreeAndNil(fDocument);
  1389. inherited Destroy;
  1390. end;
  1391. end.