cProtoBufProtoCodeGenPascal.pas 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548
  1. {******************************************************************************}
  2. { }
  3. { Library: Fundamentals 4.00 }
  4. { File name: cProtoBufProtoCodeGenPascal.pas }
  5. { File version: 0.04 }
  6. { Description: Protocol Buffer code generator for Pascal. }
  7. { }
  8. { Copyright: Copyright (c) 2012-2013, David J Butler }
  9. { All rights reserved. }
  10. { This file is licensed under the BSD License. }
  11. { See http://www.opensource.org/licenses/bsd-license.php }
  12. { Redistribution and use in source and binary forms, with }
  13. { or without modification, are permitted provided that }
  14. { the following conditions are met: }
  15. { Redistributions of source code must retain the above }
  16. { copyright notice, this list of conditions and the }
  17. { following disclaimer. }
  18. { THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND }
  19. { CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED }
  20. { WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED }
  21. { WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A }
  22. { PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL }
  23. { THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, }
  24. { INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR }
  25. { CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, }
  26. { PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF }
  27. { USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) }
  28. { HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER }
  29. { IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING }
  30. { NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE }
  31. { USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE }
  32. { POSSIBILITY OF SUCH DAMAGE. }
  33. { }
  34. { Home page: http://fundementals.sourceforge.net }
  35. { Forum: http://sourceforge.net/forum/forum.php?forum_id=2117 }
  36. { E-mail: fundamentals.library@gmail.com }
  37. { }
  38. { Revision history: }
  39. { }
  40. { 2012/04/15 0.01 Initial version: Framework }
  41. { 2012/04/16 0.02 Generates unit with record definitions. }
  42. { 2012/04/17 0.03 Refactoring. }
  43. { 2012/04/26 0.04 Imports. }
  44. { }
  45. {******************************************************************************}
  46. {$INCLUDE cProtoBuf.inc}
  47. unit cProtoBufProtoCodeGenPascal;
  48. interface
  49. uses
  50. { Fundamentals }
  51. cUtils,
  52. cDynArrays,
  53. cStrings,
  54. cProtoBufProtoNodes;
  55. type
  56. { CodeGenPascal }
  57. TCodeGenPascalUnitUsesList = class
  58. protected
  59. FList : AnsiStringArray;
  60. public
  61. procedure Add(const Name: AnsiString);
  62. function GetAsPascal: AnsiString;
  63. end;
  64. TCodeGenPascalIntfDefinitions = class
  65. protected
  66. FList : AnsiStringArray;
  67. public
  68. function HasDef(const Name: AnsiString): Boolean;
  69. function Add(const Name: AnsiString): Boolean;
  70. end;
  71. TCodeGenPascalUnitSection = class(TAnsiStringBuilder)
  72. end;
  73. TCodeGenPascalUnit = class
  74. protected
  75. FName : AnsiString;
  76. FUnitComments : AnsiString;
  77. FIntfUsesList : TCodeGenPascalUnitUsesList;
  78. FIntfSection : TCodeGenPascalUnitSection;
  79. FIntfDefs : TCodeGenPascalIntfDefinitions;
  80. FImplUsesList : TCodeGenPascalUnitUsesList;
  81. FImplSection : TCodeGenPascalUnitSection;
  82. public
  83. constructor Create;
  84. destructor Destroy; override;
  85. property Name: AnsiString read FName write FName;
  86. property UnitComments: AnsiString read FUnitComments write FUnitComments;
  87. property Intf: TCodeGenPascalUnitSection read FIntfSection;
  88. property IntfUses: TCodeGenPascalUnitUsesList read FIntfUsesList;
  89. property IntfDefs: TCodeGenPascalIntfDefinitions read FIntfDefs;
  90. property Impl: TCodeGenPascalUnitSection read FImplSection;
  91. property ImplUses: TCodeGenPascalUnitUsesList read FImplUsesList;
  92. function GetAsPascal: AnsiString;
  93. procedure Save(const Path: String);
  94. end;
  95. { ProtoPascal }
  96. TpbProtoPascalPackage = class; // forward
  97. TpbProtoPascalMessage = class; // forward
  98. TpbProtoPascalField = class; // forward
  99. TpbProtoPascalFieldType = class; // forward
  100. TpbProtoPascalEnum = class; // forward;
  101. { TpbProtoPascalEnumValue }
  102. TpbProtoPascalEnumValue = class(TpbProtoEnumValue)
  103. protected
  104. FPascalProtoName : AnsiString;
  105. FPascalName : AnsiString;
  106. function GetPascalParentEnum: TpbProtoPascalEnum;
  107. public
  108. procedure CodeGenInit;
  109. function GetPascalDeclaration: AnsiString;
  110. end;
  111. { TpbProtoPascalEnum }
  112. TpbProtoPascalEnum = class(TpbProtoEnum)
  113. protected
  114. FPascalProtoName : AnsiString;
  115. FPascalName : AnsiString;
  116. FPascalEnumValuePrefix : AnsiString;
  117. function GetPascalValue(const Idx: Integer): TpbProtoPascalEnumValue;
  118. procedure GenerateDeclaration(const AUnit: TCodeGenPascalUnit);
  119. procedure GenerateHelpers(const AUnit: TCodeGenPascalUnit);
  120. function GetPascalZeroValueName: AnsiString;
  121. public
  122. procedure CodeGenInit;
  123. procedure GenerateMessageUnit(const AUnit: TCodeGenPascalUnit);
  124. end;
  125. { TpbProtoPascalLiteral }
  126. TpbProtoPascalLiteral = class(TpbProtoLiteral)
  127. protected
  128. public
  129. procedure CodeGenInit;
  130. function GetPascalValueStr: AnsiString;
  131. end;
  132. { TpbProtoPascalFieldType }
  133. TpbProtoPascalFieldBaseKind = (
  134. bkNone,
  135. bkEnum,
  136. bkMsg,
  137. bkSimple
  138. );
  139. TpbProtoPascalFieldBaseType = class
  140. protected
  141. FParentFieldType : TpbProtoPascalFieldType;
  142. FBaseKind : TpbProtoPascalFieldBaseKind;
  143. FEnum : TpbProtoPascalEnum;
  144. FMsg : TpbProtoPascalMessage;
  145. FPascalTypeStr : AnsiString;
  146. FPascalProtoStr : AnsiString;
  147. FPascalZeroValueStr : AnsiString;
  148. public
  149. constructor Create(const AParentFieldType: TpbProtoPascalFieldType);
  150. procedure CodeGenInit;
  151. function GetPascalEncodeFieldCall(const ParBuf, ParBufSize, ParTagID, ParValue: AnsiString): AnsiString;
  152. function GetPascalEncodeValueCall(const ParBuf, ParBufSize, ParValue: AnsiString): AnsiString;
  153. function GetPascalDecodeFieldCall(const ParField, ParValue: AnsiString): AnsiString;
  154. function GetPascalDecodeValueCall(const ParBuf, ParBufSize, ParValue: AnsiString): AnsiString;
  155. function GetPascalInitInstanceCall(const ParInstance: AnsiString): AnsiString;
  156. end;
  157. TpbProtoPascalFieldType = class(TpbProtoFieldType)
  158. protected
  159. FIsArray : Boolean;
  160. FPascalBaseType : TpbProtoPascalFieldBaseType;
  161. FPascalTypeStr : AnsiString;
  162. FPascalProtoStr : AnsiString;
  163. FPascalZeroValueStr : AnsiString;
  164. FPascalDefaultValueStr : AnsiString;
  165. FPascalArrayEncodeFuncName : AnsiString;
  166. FPascalArrayDecodeFuncName : AnsiString;
  167. FPascalEncodeFuncName : AnsiString;
  168. FPascalDecodeFuncName : AnsiString;
  169. function GetPascalParentField: TpbProtoPascalField;
  170. procedure GenerateArrayHelpers(const AUnit: TCodeGenPascalUnit);
  171. public
  172. constructor Create(const AParentField: TpbProtoField);
  173. destructor Destroy; override;
  174. procedure CodeGenInit;
  175. procedure GenerateMessageUnit(const AUnit: TCodeGenPascalUnit);
  176. end;
  177. { TpbProtoPascalField }
  178. TpbProtoPascalField = class(TpbProtoField)
  179. protected
  180. FPascalProtoName : AnsiString;
  181. FPascalName : AnsiString;
  182. FPascalRecordDefinition : AnsiString;
  183. FPascalRecordInitStatement : AnsiString;
  184. FPascalRecordFinaliseStatement : AnsiString;
  185. function GetPascalFieldType: TpbProtoPascalFieldType;
  186. function GetPascalParentMessage: TpbProtoPascalMessage;
  187. function GetPascalDefaultValue: TpbProtoPascalLiteral;
  188. function IsArray: Boolean;
  189. function GetPascalEncodeFieldTypeCall(const ParBuf, ParBufSize, ParValue: AnsiString): AnsiString;
  190. function GetPascalDecodeFieldTypeCall(const ParField, ParValue: AnsiString): AnsiString;
  191. public
  192. constructor Create(const AParentMessage: TpbProtoMessage; const AFactory: TpbProtoNodeFactory);
  193. destructor Destroy; override;
  194. procedure CodeGenInit;
  195. procedure GenerateMessageUnit(const AUnit: TCodeGenPascalUnit);
  196. end;
  197. { TpbProtoPascalMessage }
  198. TpbProtoPascalMessage = class(TpbProtoMessage)
  199. protected
  200. FPascalProtoName : AnsiString;
  201. FPascalName : AnsiString;
  202. function GetPascalPackage: TpbProtoPascalPackage;
  203. function GetPascalField(const Idx: Integer): TpbProtoPascalField;
  204. function GetPascalEnum(const Idx: Integer): TpbProtoPascalEnum;
  205. function GetPascalMessage(const Idx: Integer): TpbProtoPascalMessage;
  206. procedure GenerateRecordDeclaration(const AUnit: TCodeGenPascalUnit);
  207. procedure GenerateRecordInitProc(const AUnit: TCodeGenPascalUnit);
  208. procedure GenerateRecordEncodeProc(const AUnit: TCodeGenPascalUnit);
  209. procedure GenerateRecordDecodeProc(const AUnit: TCodeGenPascalUnit);
  210. public
  211. constructor Create(const AParentNode: TpbProtoNode);
  212. destructor Destroy; override;
  213. procedure CodeGenInit;
  214. procedure GenerateMessageUnit(const AUnit: TCodeGenPascalUnit);
  215. end;
  216. { TpbProtoPascalPackage }
  217. TpbProtoPascalPackage = class(TpbProtoPackage)
  218. protected
  219. FPascalProtoName : AnsiString;
  220. FPascalBaseName : AnsiString;
  221. FMessageUnit : TCodeGenPascalUnit;
  222. function GetPascalMessage(const Idx: Integer): TpbProtoPascalMessage;
  223. function GetPascalEnum(const Idx: Integer): TpbProtoPascalEnum;
  224. function GetPascalImportedPackage(const Idx: Integer): TpbProtoPascalPackage;
  225. public
  226. constructor Create;
  227. destructor Destroy; override;
  228. property MessageUnit: TCodeGenPascalUnit read FMessageUnit;
  229. procedure CodeGenInit;
  230. procedure GenerateMessageUnit;
  231. procedure Save(const OutputPath: String);
  232. end;
  233. { TpbProtoCodeGenPascal }
  234. TpbProtoCodeGenPascal = class
  235. protected
  236. FOutputPath : String;
  237. public
  238. constructor Create;
  239. destructor Destroy; override;
  240. property OutputPath: String read FOutputPath write FOutputPath;
  241. procedure GenerateCode(const APackage: TpbProtoPackage);
  242. end;
  243. { TpbProtoPascalNodeFactory }
  244. TpbProtoPascalNodeFactory = class(TpbProtoNodeFactory)
  245. public
  246. function CreatePackage: TpbProtoPackage; override;
  247. function CreateMessage(const AParentNode: TpbProtoNode): TpbProtoMessage; override;
  248. function CreateField(const AParentMessage: TpbProtoMessage): TpbProtoField; override;
  249. function CreateFieldType(const AParentField: TpbProtoField): TpbProtoFieldType; override;
  250. function CreateLiteral(const AParentNode: TpbProtoNode): TpbProtoLiteral; override;
  251. function CreateEnum(const AParentNode: TpbProtoNode): TpbProtoEnum; override;
  252. function CreateEnumValue(const AParentEnum: TpbProtoEnum): TpbProtoEnumValue; override;
  253. end;
  254. { GetPascalProtoNodeFactory }
  255. function GetPascalProtoNodeFactory: TpbProtoPascalNodeFactory;
  256. implementation
  257. uses
  258. { System }
  259. SysUtils,
  260. Classes;
  261. const
  262. CRLF = AnsiString(#13#10);
  263. { TCodeGenPascalUnitUsesList }
  264. procedure TCodeGenPascalUnitUsesList.Add(const Name: AnsiString);
  265. begin
  266. if DynArrayPosNextA(Name, FList) >= 0 then
  267. exit;
  268. DynArrayAppendA(FList, Name);
  269. end;
  270. function TCodeGenPascalUnitUsesList.GetAsPascal: AnsiString;
  271. var L, I : Integer;
  272. begin
  273. L := Length(FList);
  274. if L = 0 then
  275. begin
  276. Result := CRLF + CRLF;
  277. exit;
  278. end;
  279. Result :=
  280. 'uses' + CRLF;
  281. for I := 0 to L - 1 do
  282. begin
  283. Result := Result + ' ' + FList[I];
  284. if I < L - 1 then
  285. Result := Result + ',' + CRLF;
  286. end;
  287. Result := Result + ';' + CRLF +
  288. CRLF +
  289. CRLF +
  290. CRLF;
  291. end;
  292. { TCodeGenPascalIntfDefinitions }
  293. function TCodeGenPascalIntfDefinitions.HasDef(const Name: AnsiString): Boolean;
  294. begin
  295. Result := DynArrayPosNextA(Name, FList) >= 0;
  296. end;
  297. function TCodeGenPascalIntfDefinitions.Add(const Name: AnsiString): Boolean;
  298. begin
  299. Result := DynArrayPosNextA(Name, FList) < 0;
  300. if not Result then
  301. exit;
  302. DynArrayAppendA(FList, Name);
  303. end;
  304. { TCodeGenPascalUnit }
  305. constructor TCodeGenPascalUnit.Create;
  306. begin
  307. inherited Create;
  308. FIntfUsesList := TCodeGenPascalUnitUsesList.Create;
  309. FIntfSection := TCodeGenPascalUnitSection.Create;
  310. FIntfDefs := TCodeGenPascalIntfDefinitions.Create;
  311. FImplUsesList := TCodeGenPascalUnitUsesList.Create;
  312. FImplSection := TCodeGenPascalUnitSection.Create;
  313. end;
  314. destructor TCodeGenPascalUnit.Destroy;
  315. begin
  316. FreeAndNil(FImplSection);
  317. FreeAndNil(FImplUsesList);
  318. FreeAndNil(FIntfDefs);
  319. FreeAndNil(FIntfSection);
  320. FreeAndNil(FIntfUsesList);
  321. inherited Destroy;
  322. end;
  323. function TCodeGenPascalUnit.GetAsPascal: AnsiString;
  324. begin
  325. Result :=
  326. FUnitComments + iifA(FUnitComments <> '', CRLF, '') +
  327. 'unit ' + FName + ';' + CRLF +
  328. CRLF +
  329. 'interface' + CRLF +
  330. CRLF +
  331. FIntfUsesList.GetAsPascal +
  332. FIntfSection.AsAnsiString +
  333. 'implementation' + CRLF +
  334. CRLF +
  335. FImplUsesList.GetAsPascal +
  336. FImplSection.AsAnsiString +
  337. 'end.' + CRLF +
  338. CRLF;
  339. end;
  340. procedure TCodeGenPascalUnit.Save(const Path: String);
  341. var
  342. FileName : String;
  343. FileData : AnsiString;
  344. FileStream : TFileStream;
  345. begin
  346. FileName := Path + String(FName) + '.pas';
  347. FileData := GetAsPascal;
  348. FileStream := TFileStream.Create(FileName, fmCreate);
  349. try
  350. FileStream.WriteBuffer(PAnsiChar(FileData)^, Length(FileData));
  351. finally
  352. FileStream.Free;
  353. end;
  354. end;
  355. { ProtoPascal }
  356. const
  357. ProtoFieldBaseTypeToPascalBaseTypeStr: array[TpbProtoFieldBaseType] of AnsiString = (
  358. '',
  359. 'Double',
  360. 'Single',
  361. 'LongInt',
  362. 'Int64',
  363. 'LongWord',
  364. 'UInt64',
  365. 'LongInt',
  366. 'Int64',
  367. 'LongWord',
  368. 'UInt64',
  369. 'LongInt',
  370. 'Int64',
  371. 'Boolean',
  372. 'AnsiString',
  373. 'RawByteString',
  374. ''
  375. );
  376. ProtoFieldBaseTypeToPascalZeroValueStr: array[TpbProtoFieldBaseType] of AnsiString = (
  377. '',
  378. '0.0',
  379. '0.0',
  380. '0',
  381. '0',
  382. '0',
  383. '0',
  384. '0',
  385. '0',
  386. '0',
  387. '0',
  388. '0',
  389. '0',
  390. 'False',
  391. '''''',
  392. '''''',
  393. ''
  394. );
  395. ProtoFieldTypeToPascalStr : array[TpbProtoFieldBaseType] of AnsiString = (
  396. '',
  397. 'Double',
  398. 'Float',
  399. 'Int32',
  400. 'Int64',
  401. 'UInt32',
  402. 'UInt64',
  403. 'SInt32',
  404. 'SInt64',
  405. 'Fixed32',
  406. 'Fixed64',
  407. 'SFixed32',
  408. 'SFixed64',
  409. 'Bool',
  410. 'String',
  411. 'Bytes',
  412. ''
  413. );
  414. // converts a name from the .proto file to a name that follows Pascal
  415. // conventions, i.e. camel case, no underscores
  416. function ProtoNameToPascalProtoName(const AName: AnsiString): AnsiString;
  417. var S : AnsiString;
  418. I : Integer;
  419. begin
  420. S := AName;
  421. // replace _xxx with _Xxx
  422. repeat
  423. I := PosStrA('_', S);
  424. if I > 0 then
  425. begin
  426. Delete(S, I, 1);
  427. if I <= Length(S) then
  428. S[I] := AsciiUpCaseA(S[I]);
  429. end;
  430. until I = 0;
  431. // first character upper case
  432. S := AsciiFirstUpA(S);
  433. // return Pascal name
  434. Result := S;
  435. end;
  436. { TpbProtoPascalEnumValue }
  437. function TpbProtoPascalEnumValue.GetPascalParentEnum: TpbProtoPascalEnum;
  438. begin
  439. Result := FParentEnum as TpbProtoPascalEnum;
  440. end;
  441. procedure TpbProtoPascalEnumValue.CodeGenInit;
  442. begin
  443. FPascalProtoName := ProtoNameToPascalProtoName(FName);
  444. FPascalName := GetPascalParentEnum.FPascalEnumValuePrefix + FPascalProtoName;
  445. end;
  446. function TpbProtoPascalEnumValue.GetPascalDeclaration: AnsiString;
  447. begin
  448. Result := FPascalName + ' = ' + IntToStringA(FValue);
  449. end;
  450. { TpbProtoPascalEnum }
  451. function TpbProtoPascalEnum.GetPascalValue(const Idx: Integer): TpbProtoPascalEnumValue;
  452. begin
  453. Result := GetValue(Idx) as TpbProtoPascalEnumValue;
  454. end;
  455. function TpbProtoPascalEnum.GetPascalZeroValueName: AnsiString;
  456. begin
  457. if GetValueCount = 0 then
  458. Result := ''
  459. else
  460. Result := GetPascalValue(0).FPascalName;
  461. end;
  462. procedure TpbProtoPascalEnum.CodeGenInit;
  463. var I : Integer;
  464. begin
  465. FPascalProtoName := ProtoNameToPascalProtoName(FName);
  466. FPascalName := 'T' + FPascalProtoName;
  467. FPascalEnumValuePrefix := FName;
  468. AsciiConvertLowerA(FPascalEnumValuePrefix);
  469. for I := 0 to GetValueCount - 1 do
  470. GetPascalValue(I).CodeGenInit;
  471. end;
  472. procedure TpbProtoPascalEnum.GenerateDeclaration(const AUnit: TCodeGenPascalUnit);
  473. var
  474. I, L : Integer;
  475. begin
  476. with AUnit do
  477. begin
  478. Intf.AppendLn('{ ' + FPascalName + ' }');
  479. Intf.AppendLn;
  480. Intf.AppendLn('type');
  481. Intf.AppendLn(' ' + FPascalName + ' = (');
  482. L := GetValueCount;
  483. for I := 0 to L - 1 do
  484. begin
  485. Intf.Append(' ' + GetPascalValue(I).GetPascalDeclaration);
  486. if I < L - 1 then
  487. Intf.AppendCh(',');
  488. Intf.AppendLn;
  489. end;
  490. Intf.AppendLn(' );');
  491. Intf.AppendLn;
  492. end;
  493. end;
  494. procedure TpbProtoPascalEnum.GenerateHelpers(const AUnit: TCodeGenPascalUnit);
  495. var
  496. Proto : AnsiString;
  497. begin
  498. with AUnit do
  499. begin
  500. Impl.AppendLn('{ ' + FPascalName + ' }');
  501. Impl.AppendLn;
  502. Proto := 'function pbEncodeValue' + FPascalProtoName + '(var Buf; const BufSize: Integer; const Value: ' + FPascalName + '): Integer;';
  503. Intf.AppendLn(Proto);
  504. Impl.AppendLn(Proto);
  505. Impl.AppendLn('begin');
  506. Impl.AppendLn(' Result := pbEncodeValueInt32(Buf, BufSize, Ord(Value));');
  507. Impl.AppendLn('end;');
  508. Impl.AppendLn;
  509. Proto := 'function pbEncodeField' + FPascalProtoName + '(var Buf; const BufSize: Integer; const FieldNum: Integer; const Value: ' + FPascalName + '): Integer;';
  510. Intf.AppendLn(Proto);
  511. Impl.AppendLn(Proto);
  512. Impl.AppendLn('begin');
  513. Impl.AppendLn(' Result := pbEncodeFieldInt32(Buf, BufSize, FieldNum, Ord(Value));');
  514. Impl.AppendLn('end;');
  515. Impl.AppendLn;
  516. Proto := 'function pbDecodeValue' + FPascalProtoName + '(const Buf; const BufSize: Integer; var Value: ' + FPascalName + '): Integer;';
  517. Intf.AppendLn(Proto);
  518. Impl.AppendLn(Proto);
  519. Impl.AppendLn('var I : LongInt;');
  520. Impl.AppendLn('begin');
  521. Impl.AppendLn(' Result := pbDecodeValueInt32(Buf, BufSize, I);');
  522. Impl.AppendLn(' Value := ' + FPascalName + '(I);');
  523. Impl.AppendLn('end;');
  524. Impl.AppendLn;
  525. Proto := 'procedure pbDecodeField' + FPascalProtoName + '(const Field: TpbProtoBufDecodeField; var Value: ' + FPascalName + ');';
  526. Intf.AppendLn(Proto);
  527. Impl.AppendLn(Proto);
  528. Impl.AppendLn('var I : LongInt;');
  529. Impl.AppendLn('begin');
  530. Impl.AppendLn(' pbDecodeFieldInt32(Field, I);');
  531. Impl.AppendLn(' Value := ' + FPascalName + '(I);');
  532. Impl.AppendLn('end;');
  533. Impl.AppendLn;
  534. end;
  535. end;
  536. procedure TpbProtoPascalEnum.GenerateMessageUnit(const AUnit: TCodeGenPascalUnit);
  537. begin
  538. GenerateDeclaration(AUnit);
  539. GenerateHelpers(AUnit);
  540. AUnit.Intf.AppendLn;
  541. AUnit.Intf.AppendLn;
  542. AUnit.Intf.AppendLn;
  543. AUnit.Impl.AppendLn;
  544. AUnit.Impl.AppendLn;
  545. end;
  546. { TpbProtoPascalLiteral }
  547. procedure TpbProtoPascalLiteral.CodeGenInit;
  548. begin
  549. end;
  550. function TpbProtoPascalLiteral.GetPascalValueStr: AnsiString;
  551. var
  552. V : TpbProtoNode;
  553. begin
  554. case FLiteralType of
  555. pltInteger : Result := IntToStringA(FLiteralInt);
  556. pltFloat : Result := FloatToStringA(FLiteralFloat);
  557. pltString : Result := StrQuoteA(FLiteralStr, '''');
  558. pltBoolean : Result := iifA(FLiteralBool, 'True', 'False');
  559. pltIdentifier :
  560. begin
  561. V := LiteralIdenValue;
  562. if V is TpbProtoPascalEnumValue then
  563. Result := TpbProtoPascalEnumValue(V).FPascalName
  564. else
  565. Result := '';
  566. end;
  567. else
  568. raise EpbProtoNode.Create('Literal type not supported');
  569. end;
  570. end;
  571. { TpbProtoPascalFieldBaseType }
  572. constructor TpbProtoPascalFieldBaseType.Create(const AParentFieldType: TpbProtoPascalFieldType);
  573. begin
  574. inherited Create;
  575. FParentFieldType := AParentFieldType;
  576. FBaseKind := bkNone;
  577. end;
  578. procedure TpbProtoPascalFieldBaseType.CodeGenInit;
  579. var T : TpbProtoNode;
  580. B : TpbProtoFieldBaseType;
  581. begin
  582. if FParentFieldType.IsIdenType then
  583. begin
  584. T := FParentFieldType.IdenType;
  585. if T is TpbProtoPascalEnum then
  586. begin
  587. FBaseKind := bkEnum;
  588. FEnum := TpbProtoPascalEnum(T);
  589. FPascalTypeStr := FEnum.FPascalName;
  590. FPascalProtoStr := FEnum.FPascalProtoName;
  591. FPascalZeroValueStr := FEnum.GetPascalZeroValueName;
  592. end
  593. else
  594. if T is TpbProtoPascalMessage then
  595. begin
  596. FBaseKind := bkMsg;
  597. FMsg := TpbProtoPascalMessage(T);
  598. FPascalTypeStr := FMsg.FPascalName;
  599. FPascalProtoStr := FMsg.FPascalProtoName;
  600. FPascalZeroValueStr := '';
  601. end
  602. else
  603. raise EpbProtoNode.CreateFmt('Unresolved identifier: %s', [FParentFieldType.IdenStr]);
  604. end
  605. else
  606. begin
  607. FBaseKind := bkSimple;
  608. B := FParentFieldType.FBaseType;
  609. FPascalTypeStr := ProtoFieldBaseTypeToPascalBaseTypeStr[B];
  610. FPascalProtoStr := ProtoFieldTypeToPascalStr[B];
  611. FPascalZeroValueStr := ProtoFieldBaseTypeToPascalZeroValueStr[B];
  612. end;
  613. end;
  614. function TpbProtoPascalFieldBaseType.GetPascalEncodeFieldCall(const ParBuf, ParBufSize, ParTagID, ParValue: AnsiString): AnsiString;
  615. begin
  616. case FBaseKind of
  617. bkSimple :
  618. Result := 'pbEncodeField' + FPascalProtoStr +
  619. '(' + ParBuf + ', ' + ParBufSize + ', ' + ParTagID + ', ' + ParValue + ')';
  620. bkEnum :
  621. Result := 'pbEncodeField' + FEnum.FName +
  622. '(' + ParBuf + ', ' + ParBufSize + ', ' + ParTagID + ', ' + ParValue + ')';
  623. bkMsg :
  624. Result := 'pbEncodeField' + FMsg.FPascalProtoName +
  625. '(' + ParBuf + ', ' + ParBufSize + ', ' + ParTagID + ', ' + ParValue + ')';
  626. else
  627. Result := '';
  628. end;
  629. end;
  630. function TpbProtoPascalFieldBaseType.GetPascalEncodeValueCall(const ParBuf, ParBufSize, ParValue: AnsiString): AnsiString;
  631. begin
  632. case FBaseKind of
  633. bkSimple :
  634. Result := 'pbEncodeValue' + FPascalProtoStr +
  635. '(' + ParBuf + ', ' + ParBufSize + ', ' + ParValue + ')';
  636. bkEnum :
  637. Result := 'pbEncodeValue' + FEnum.FPascalProtoName +
  638. '(' + ParBuf + ', ' + ParBufSize + ', ' + ParValue + ')';
  639. bkMsg :
  640. Result := 'pbEncodeValue' + FMsg.FPascalProtoName +
  641. '(' + ParBuf + ', ' + ParBufSize + ', ' + ParValue + ')';
  642. else
  643. Result := '';
  644. end;
  645. end;
  646. function TpbProtoPascalFieldBaseType.GetPascalDecodeFieldCall(const ParField, ParValue: AnsiString): AnsiString;
  647. begin
  648. case FBaseKind of
  649. bkSimple :
  650. Result := 'pbDecodeField' + FPascalProtoStr +
  651. '(' + ParField + ', ' + ParValue + ')';
  652. bkEnum :
  653. Result := 'pbDecodeField' + FEnum.FPascalProtoName +
  654. '(' + ParField + ', ' + ParValue + ')';
  655. bkMsg :
  656. Result := 'pbDecodeField' + FMsg.FPascalProtoName +
  657. '(' + ParField + ', ' + ParValue + ')';
  658. else
  659. Result := '';
  660. end;
  661. end;
  662. function TpbProtoPascalFieldBaseType.GetPascalDecodeValueCall(const ParBuf, ParBufSize, ParValue: AnsiString): AnsiString;
  663. begin
  664. case FBaseKind of
  665. bkSimple :
  666. Result := 'pbDecodeValue' + FPascalProtoStr +
  667. '(' + ParBuf + ', ' + ParBufSize + ', ' + ParValue + ')';
  668. bkEnum :
  669. Result := 'pbDecodeValue' + FEnum.FPascalProtoName +
  670. '(' + ParBuf + ', ' + ParBufSize + ', ' + ParValue + ')';
  671. bkMsg :
  672. Result := 'pbDecodeValue' + FMsg.FPascalProtoName +
  673. '(' + ParBuf + ', ' + ParBufSize + ', ' + ParValue + ')';
  674. else
  675. Result := '';
  676. end;
  677. end;
  678. function TpbProtoPascalFieldBaseType.GetPascalInitInstanceCall(const ParInstance: AnsiString): AnsiString;
  679. begin
  680. case FBaseKind of
  681. bkMsg : Result := FMsg.FPascalProtoName + 'Init(' + ParInstance + ')';
  682. else
  683. Result := '';
  684. end;
  685. end;
  686. { TpbProtoPascalFieldType }
  687. constructor TpbProtoPascalFieldType.Create(const AParentField: TpbProtoField);
  688. begin
  689. inherited Create(AParentField);
  690. FPascalBaseType := TpbProtoPascalFieldBaseType.Create(self);
  691. end;
  692. destructor TpbProtoPascalFieldType.Destroy;
  693. begin
  694. FreeAndNil(FPascalBaseType);
  695. inherited Destroy;
  696. end;
  697. function TpbProtoPascalFieldType.GetPascalParentField: TpbProtoPascalField;
  698. begin
  699. Result := FParentField as TpbProtoPascalField;
  700. end;
  701. procedure TpbProtoPascalFieldType.CodeGenInit;
  702. begin
  703. FPascalBaseType.CodeGenInit;
  704. FIsArray := FParentField.Cardinality = pfcRepeated;
  705. if FIsArray then
  706. begin
  707. FPascalProtoStr := 'DynArray' + FPascalBaseType.FPascalProtoStr;
  708. FPascalTypeStr := 'T' + FPascalProtoStr;
  709. FPascalZeroValueStr := 'nil';
  710. FPascalDefaultValueStr := 'nil';
  711. FPascalArrayEncodeFuncName := 'pbEncodeField' + FPascalProtoStr;
  712. FPascalArrayDecodeFuncName := 'pbDecodeField' + FPascalProtoStr;
  713. if FParentField.OptionPacked then
  714. begin
  715. FPascalEncodeFuncName := FPascalArrayEncodeFuncName + '_Packed';
  716. FPascalDecodeFuncName := FPascalArrayDecodeFuncName + '_Packed';
  717. end
  718. else
  719. begin
  720. FPascalEncodeFuncName := FPascalArrayEncodeFuncName;
  721. FPascalDecodeFuncName := FPascalArrayDecodeFuncName;
  722. end;
  723. end
  724. else
  725. begin
  726. FPascalTypeStr := FPascalBaseType.FPascalTypeStr;
  727. FPascalZeroValueStr := FPascalBaseType.FPascalZeroValueStr;
  728. if FParentField.DefaultValue.LiteralType = pltNone then
  729. FPascalDefaultValueStr := FPascalZeroValueStr
  730. else
  731. FPascalDefaultValueStr := GetPascalParentField.GetPascalDefaultValue.GetPascalValueStr;
  732. FPascalArrayEncodeFuncName := '';
  733. FPascalArrayDecodeFuncName := '';
  734. FPascalEncodeFuncName := '';
  735. end;
  736. end;
  737. procedure TpbProtoPascalFieldType.GenerateArrayHelpers(const AUnit: TCodeGenPascalUnit);
  738. var
  739. Proto : AnsiString;
  740. CommentLine : AnsiString;
  741. S : AnsiString;
  742. begin
  743. with AUnit do
  744. if IntfDefs.Add(FPascalTypeStr) then
  745. begin
  746. CommentLine := '{ ' + FPascalTypeStr + ' }';
  747. Intf.AppendLn(CommentLine);
  748. Intf.AppendLn;
  749. Impl.AppendLn(CommentLine);
  750. Impl.AppendLn;
  751. Intf.AppendLn('type');
  752. Intf.AppendLn(' ' + FPascalTypeStr + ' = array of ' + FPascalBaseType.FPascalTypeStr + ';');
  753. Intf.AppendLn;
  754. Proto :=
  755. 'function ' + FPascalArrayEncodeFuncName +
  756. '(var Buf; const BufSize: Integer; const FieldNum: Integer; const Value: ' + FPascalTypeStr + '): Integer;';
  757. Intf.AppendLn(Proto);
  758. Impl.AppendLn(Proto);
  759. Impl.AppendLn('var');
  760. Impl.AppendLn(' P : PByte;');
  761. Impl.AppendLn(' I, L, N : Integer;');
  762. Impl.AppendLn('begin');
  763. Impl.AppendLn(' P := @Buf;');
  764. Impl.AppendLn(' L := BufSize;');
  765. Impl.AppendLn(' for I := 0 to Length(Value) - 1 do');
  766. Impl.AppendLn(' begin');
  767. Impl.AppendLn(' N := ' + FPascalBaseType.GetPascalEncodeFieldCall('P^', 'L', 'FieldNum', 'Value[I]') + ';');
  768. Impl.AppendLn(' Inc(P, N);');
  769. Impl.AppendLn(' Dec(L, N);');
  770. Impl.AppendLn(' end;');
  771. Impl.AppendLn(' Result := BufSize - L;');
  772. Impl.AppendLn('end;');
  773. Impl.AppendLn;
  774. Proto :=
  775. 'function ' + FPascalArrayEncodeFuncName + '_Packed' +
  776. '(var Buf; const BufSize: Integer; const FieldNum: Integer; const Value: ' + FPascalTypeStr + '): Integer;';
  777. Intf.AppendLn(Proto);
  778. Impl.AppendLn(Proto);
  779. Impl.AppendLn('var');
  780. Impl.AppendLn(' P : PByte;');
  781. Impl.AppendLn(' I, T, L, N : Integer;');
  782. Impl.AppendLn('begin');
  783. Impl.AppendLn(' P := @Buf;');
  784. Impl.AppendLn(' T := 0;');
  785. Impl.AppendLn(' for I := 0 to Length(Value) - 1 do');
  786. Impl.AppendLn(' Inc(T, ' + FPascalBaseType.GetPascalEncodeValueCall('P^', '0', 'Value[I]') + ');');
  787. Impl.AppendLn(' L := BufSize;');
  788. Impl.AppendLn(' N := pbEncodeFieldVarBytesHdr(P^, L, FieldNum, T);');
  789. Impl.AppendLn(' Inc(P, N);');
  790. Impl.AppendLn(' Dec(L, N);');
  791. Impl.AppendLn(' for I := 0 to Length(Value) - 1 do');
  792. Impl.AppendLn(' begin');
  793. Impl.AppendLn(' N := ' + FPascalBaseType.GetPascalEncodeValueCall('P^', 'L', 'Value[I]') + ';');
  794. Impl.AppendLn(' Inc(P, N);');
  795. Impl.AppendLn(' Dec(L, N);');
  796. Impl.AppendLn(' end;');
  797. Impl.AppendLn(' Result := BufSize - L;');
  798. Impl.AppendLn('end;');
  799. Impl.AppendLn;
  800. Proto :=
  801. 'procedure ' + FPascalArrayDecodeFuncName +
  802. '(const Field: TpbProtoBufDecodeField; var Value: ' + FPascalTypeStr + ');';
  803. Intf.AppendLn(Proto);
  804. Impl.AppendLn(Proto);
  805. Impl.AppendLn('var');
  806. Impl.AppendLn(' L : Integer;');
  807. Impl.AppendLn('begin');
  808. Impl.AppendLn(' L := Length(Value);');
  809. Impl.AppendLn(' SetLength(Value, L + 1);');
  810. S := FPascalBaseType.GetPascalInitInstanceCall('Value[L]');
  811. if S <> '' then
  812. Impl.AppendLn(' ' + S + ';');
  813. Impl.AppendLn(' ' + FPascalBaseType.GetPascalDecodeFieldCall('Field', 'Value[L]') + ';');
  814. Impl.AppendLn('end;');
  815. Impl.AppendLn;
  816. Proto :=
  817. 'procedure ' + FPascalArrayDecodeFuncName + '_Packed' +
  818. '(const Field: TpbProtoBufDecodeField; var Value: ' + FPascalTypeStr + ');';
  819. Intf.AppendLn(Proto);
  820. Impl.AppendLn(Proto);
  821. Impl.AppendLn('var');
  822. Impl.AppendLn(' P : PByte;');
  823. Impl.AppendLn(' L, N, I : Integer;');
  824. Impl.AppendLn('begin');
  825. Impl.AppendLn(' P := Field.ValueVarBytesPtr;');
  826. Impl.AppendLn(' L := 0;');
  827. Impl.AppendLn(' N := Field.ValueVarBytesLen;');
  828. Impl.AppendLn(' while N > 0 do');
  829. Impl.AppendLn(' begin');
  830. Impl.AppendLn(' SetLength(Value, L + 1);');
  831. S := FPascalBaseType.GetPascalInitInstanceCall('Value[L]');
  832. if S <> '' then
  833. Impl.AppendLn(' ' + S + ';');
  834. Impl.AppendLn(' I := ' + FPascalBaseType.GetPascalDecodeValueCall('P^', 'N', 'Value[L]') + ';');
  835. Impl.AppendLn(' Inc(L);');
  836. Impl.AppendLn(' Inc(P, I);');
  837. Impl.AppendLn(' Dec(N, I);');
  838. Impl.AppendLn(' end;');
  839. Impl.AppendLn('end;');
  840. Impl.AppendLn;
  841. Impl.AppendLn;
  842. Impl.AppendLn;
  843. Intf.AppendLn;
  844. Intf.AppendLn;
  845. Intf.AppendLn;
  846. end;
  847. end;
  848. procedure TpbProtoPascalFieldType.GenerateMessageUnit(const AUnit: TCodeGenPascalUnit);
  849. begin
  850. if FIsArray then
  851. GenerateArrayHelpers(AUnit);
  852. end;
  853. { TpbProtoPascalField }
  854. constructor TpbProtoPascalField.Create(const AParentMessage: TpbProtoMessage; const AFactory: TpbProtoNodeFactory);
  855. begin
  856. inherited Create(AParentMessage, AFactory);
  857. end;
  858. destructor TpbProtoPascalField.Destroy;
  859. begin
  860. inherited Destroy;
  861. end;
  862. function TpbProtoPascalField.GetPascalFieldType: TpbProtoPascalFieldType;
  863. begin
  864. Result := FFieldType as TpbProtoPascalFieldType;
  865. end;
  866. function TpbProtoPascalField.GetPascalParentMessage: TpbProtoPascalMessage;
  867. begin
  868. Result := FParentMessage as TpbProtoPascalMessage;
  869. end;
  870. function TpbProtoPascalField.GetPascalDefaultValue: TpbProtoPascalLiteral;
  871. begin
  872. Result := FDefaultValue as TpbProtoPascalLiteral;
  873. end;
  874. function TpbProtoPascalField.IsArray: Boolean;
  875. begin
  876. Result := FCardinality = pfcRepeated;
  877. end;
  878. procedure TpbProtoPascalField.CodeGenInit;
  879. begin
  880. FPascalProtoName := ProtoNameToPascalProtoName(FName);
  881. FPascalName := FPascalProtoName;
  882. GetPascalFieldType.CodeGenInit;
  883. FPascalRecordDefinition :=
  884. FPascalName + ' : ' + GetPascalFieldType.FPascalTypeStr + ';';
  885. if not GetPascalFieldType.FIsArray and (GetPascalFieldType.FPascalBaseType.FBaseKind = bkMsg) then
  886. begin
  887. FPascalRecordInitStatement :=
  888. GetPascalFieldType.FPascalBaseType.FMsg.FPascalProtoName + 'Init(' + FPascalName + ');';
  889. FPascalRecordFinaliseStatement :=
  890. GetPascalFieldType.FPascalBaseType.FMsg.FPascalProtoName + 'Finalise(' + FPascalName + ');';
  891. end
  892. else
  893. begin
  894. FPascalRecordInitStatement :=
  895. FPascalName + ' := ' + GetPascalFieldType.FPascalDefaultValueStr + ';';
  896. FPascalRecordFinaliseStatement := '';
  897. end;
  898. end;
  899. procedure TpbProtoPascalField.GenerateMessageUnit(const AUnit: TCodeGenPascalUnit);
  900. begin
  901. GetPascalFieldType.GenerateMessageUnit(AUnit);
  902. end;
  903. function TpbProtoPascalField.GetPascalEncodeFieldTypeCall(const ParBuf, ParBufSize, ParValue: AnsiString): AnsiString;
  904. begin
  905. if IsArray then
  906. Result := GetPascalFieldType.FPascalEncodeFuncName +
  907. '(' + ParBuf + ', ' + ParBufSize + ', ' + IntToStringA(FTagID) + ', ' + ParValue + ')'
  908. else
  909. Result := GetPascalFieldType.FPascalBaseType.GetPascalEncodeFieldCall(
  910. ParBuf, ParBufSize, IntToStringA(FTagID), ParValue);
  911. end;
  912. function TpbProtoPascalField.GetPascalDecodeFieldTypeCall(const ParField, ParValue: AnsiString): AnsiString;
  913. begin
  914. if IsArray then
  915. Result := GetPascalFieldType.FPascalDecodeFuncName + '(' + ParField + ', ' + ParValue + ')'
  916. else
  917. Result := GetPascalFieldType.FPascalBaseType.GetPascalDecodeFieldCall(ParField, ParValue);
  918. end;
  919. { TpbProtoPascalMessage }
  920. constructor TpbProtoPascalMessage.Create(const AParentNode: TpbProtoNode);
  921. begin
  922. inherited Create(AParentNode);
  923. end;
  924. destructor TpbProtoPascalMessage.Destroy;
  925. begin
  926. inherited Destroy;
  927. end;
  928. function TpbProtoPascalMessage.GetPascalPackage: TpbProtoPascalPackage;
  929. begin
  930. Result := FParentNode as TpbProtoPascalPackage;
  931. end;
  932. function TpbProtoPascalMessage.GetPascalField(const Idx: Integer): TpbProtoPascalField;
  933. begin
  934. Result := GetField(Idx) as TpbProtoPascalField;
  935. end;
  936. function TpbProtoPascalMessage.GetPascalEnum(const Idx: Integer): TpbProtoPascalEnum;
  937. begin
  938. Result := GetEnum(Idx) as TpbProtoPascalEnum;
  939. end;
  940. function TpbProtoPascalMessage.GetPascalMessage(const Idx: Integer): TpbProtoPascalMessage;
  941. begin
  942. Result := GetMessage(Idx) as TpbProtoPascalMessage;
  943. end;
  944. procedure TpbProtoPascalMessage.CodeGenInit;
  945. var I : Integer;
  946. begin
  947. FPascalProtoName := ProtoNameToPascalProtoName(FName) + 'Record';
  948. FPascalName := 'T' + FPascalProtoName;
  949. for I := 0 to GetEnumCount - 1 do
  950. GetPascalEnum(I).CodeGenInit;
  951. for I := 0 to GetMessageCount - 1 do
  952. GetPascalMessage(I).CodeGenInit;
  953. for I := 0 to GetFieldCount - 1 do
  954. GetPascalField(I).CodeGenInit;
  955. end;
  956. procedure TpbProtoPascalMessage.GenerateRecordDeclaration(const AUnit: TCodeGenPascalUnit);
  957. var
  958. I : Integer;
  959. begin
  960. with AUnit do
  961. begin
  962. Intf.AppendLn('type');
  963. Intf.AppendLn(' ' + FPascalName + ' = record');
  964. for I := 0 to GetFieldCount - 1 do
  965. Intf.AppendLn(' ' + GetPascalField(I).FPascalRecordDefinition);
  966. Intf.AppendLn(' end;');
  967. Intf.AppendLn(' P' + FPascalProtoName + ' = ^T' + FPascalProtoName + ';');
  968. Intf.AppendLn;
  969. end;
  970. end;
  971. procedure TpbProtoPascalMessage.GenerateRecordInitProc(const AUnit: TCodeGenPascalUnit);
  972. var
  973. I : Integer;
  974. Proto, S : AnsiString;
  975. begin
  976. with AUnit do
  977. begin
  978. Proto := 'procedure ' + FPascalProtoName + 'Init(var A: ' + FPascalName + ');';
  979. Intf.AppendLn(Proto);
  980. Impl.AppendLn(Proto);
  981. Impl.AppendLn('begin');
  982. Impl.AppendLn(' with A do');
  983. Impl.AppendLn(' begin');
  984. for I := 0 to GetFieldCount - 1 do
  985. Impl.AppendLn(' ' + GetPascalField(I).FPascalRecordInitStatement);
  986. Impl.AppendLn(' end;');
  987. Impl.AppendLn('end;');
  988. Impl.AppendLn;
  989. Proto := 'procedure ' + FPascalProtoName + 'Finalise(var A: ' + FPascalName + ');';
  990. Intf.AppendLn(Proto);
  991. Impl.AppendLn(Proto);
  992. Impl.AppendLn('begin');
  993. Impl.AppendLn(' with A do');
  994. Impl.AppendLn(' begin');
  995. for I := GetFieldCount - 1 downto 0 do
  996. begin
  997. S := GetPascalField(I).FPascalRecordFinaliseStatement;
  998. if S <> '' then
  999. Impl.AppendLn(' ' + S);
  1000. end;
  1001. Impl.AppendLn(' end;');
  1002. Impl.AppendLn('end;');
  1003. Impl.AppendLn;
  1004. end;
  1005. end;
  1006. procedure TpbProtoPascalMessage.GenerateRecordEncodeProc(const AUnit: TCodeGenPascalUnit);
  1007. var
  1008. I, L : Integer;
  1009. F : TpbProtoPascalField;
  1010. Proto : AnsiString;
  1011. EncodeDataProcName : AnsiString;
  1012. EncodeValueProcName : AnsiString;
  1013. EncodeFieldProcName : AnsiString;
  1014. begin
  1015. with AUnit do
  1016. begin
  1017. EncodeDataProcName := 'pbEncodeData' + FPascalProtoName;
  1018. Proto := 'function ' + EncodeDataProcName + '(var Buf; const BufSize: Integer; const A: ' + FPascalName + '): Integer;';
  1019. Intf.AppendLn(Proto);
  1020. Impl.AppendLn(Proto);
  1021. Impl.AppendLn('var');
  1022. Impl.AppendLn(' P : PByte;');
  1023. Impl.AppendLn(' L : Integer;');
  1024. Impl.AppendLn(' I : Integer;');
  1025. Impl.AppendLn('begin');
  1026. Impl.AppendLn(' P := @Buf;');
  1027. Impl.AppendLn(' L := BufSize;');
  1028. L := GetFieldCount;
  1029. for I := 0 to L - 1 do
  1030. begin
  1031. F := GetPascalField(I);
  1032. Impl.AppendLn(' I := ' + F.GetPascalEncodeFieldTypeCall('P^', 'L', 'A.' + F.FPascalName) + ';');
  1033. Impl.AppendLn(' Dec(L, I);');
  1034. if I < L - 1 then
  1035. Impl.AppendLn(' Inc(P, I);');
  1036. end;
  1037. Impl.AppendLn(' Result := BufSize - L;');
  1038. Impl.AppendLn('end;');
  1039. Impl.AppendLn;
  1040. EncodeValueProcName := 'pbEncodeValue' + FPascalProtoName;
  1041. Proto := 'function ' + EncodeValueProcName + '(var Buf; const BufSize: Integer; const A: ' + FPascalName + '): Integer;';
  1042. Intf.AppendLn(Proto);
  1043. Impl.AppendLn(Proto);
  1044. Impl.AppendLn('var');
  1045. Impl.AppendLn(' P : PByte;');
  1046. Impl.AppendLn(' L, N, I : Integer;');
  1047. Impl.AppendLn('begin');
  1048. Impl.AppendLn(' P := @Buf;');
  1049. Impl.AppendLn(' L := BufSize;');
  1050. Impl.AppendLn(' N := ' + EncodeDataProcName + '(P^, 0, A);');
  1051. Impl.AppendLn(' I := pbEncodeValueInt32(P^, L, N);');
  1052. Impl.AppendLn(' Inc(P, I);');
  1053. Impl.AppendLn(' Dec(L, I);');
  1054. Impl.AppendLn(' I := ' + EncodeDataProcName + '(P^, L, A);');
  1055. Impl.AppendLn(' Assert(I = N);');
  1056. Impl.AppendLn(' Dec(L, I);');
  1057. Impl.AppendLn(' Result := BufSize - L;');
  1058. Impl.AppendLn('end;');
  1059. Impl.AppendLn;
  1060. EncodeFieldProcName := 'pbEncodeField' + FPascalProtoName;
  1061. Proto := 'function ' + EncodeFieldProcName + '(var Buf; const BufSize: Integer; const FieldNum: Integer; const A: ' + FPascalName + '): Integer;';
  1062. Intf.AppendLn(Proto);
  1063. Impl.AppendLn(Proto);
  1064. Impl.AppendLn('var');
  1065. Impl.AppendLn(' P : PByte;');
  1066. Impl.AppendLn(' L : Integer;');
  1067. Impl.AppendLn(' I : Integer;');
  1068. Impl.AppendLn('begin');
  1069. Impl.AppendLn(' P := @Buf;');
  1070. Impl.AppendLn(' L := BufSize;');
  1071. Impl.AppendLn(' I := pbEncodeFieldKey(P^, L, FieldNum, pwtVarBytes);');
  1072. Impl.AppendLn(' Dec(L, I);');
  1073. Impl.AppendLn(' Inc(P, I);');
  1074. Impl.AppendLn(' I := ' + EncodeValueProcName + '(P^, L, A);');
  1075. Impl.AppendLn(' Dec(L, I);');
  1076. Impl.AppendLn(' Result := BufSize - L;');
  1077. Impl.AppendLn('end;');
  1078. Impl.AppendLn;
  1079. end;
  1080. end;
  1081. procedure TpbProtoPascalMessage.GenerateRecordDecodeProc(const AUnit: TCodeGenPascalUnit);
  1082. var
  1083. I, L : Integer;
  1084. F : TpbProtoPascalField;
  1085. CallbackName : AnsiString;
  1086. Proto : AnsiString;
  1087. begin
  1088. with AUnit do
  1089. begin
  1090. CallbackName := 'pbDecodeField' + FPascalProtoName + '_CallbackProc';
  1091. Impl.AppendLn('procedure ' + CallbackName + '(const Field: TpbProtoBufDecodeField; const Data: Pointer);');
  1092. Impl.AppendLn('var');
  1093. Impl.AppendLn(' A : P' + FPascalProtoName + ';');
  1094. Impl.AppendLn('begin');
  1095. Impl.AppendLn(' A := Data;');
  1096. Impl.AppendLn(' case Field.FieldNum of');
  1097. L := GetFieldCount;
  1098. for I := 0 to L - 1 do
  1099. begin
  1100. F := GetPascalField(I);
  1101. Impl.AppendLn(' ' + IntToStringA(F.FTagID) + ' : ' + F.GetPascalDecodeFieldTypeCall('Field', 'A^.' + F.FPascalName) + ';');
  1102. end;
  1103. Impl.AppendLn(' end;');
  1104. Impl.AppendLn('end;');
  1105. Impl.AppendLn;
  1106. Proto := 'function pbDecodeValue' + FPascalProtoName + '(const Buf; const BufSize: Integer; var Value: ' + FPascalName + '): Integer;';
  1107. Intf.AppendLn(Proto);
  1108. Impl.AppendLn(Proto);
  1109. Impl.AppendLn('var');
  1110. Impl.AppendLn(' P : PByte;');
  1111. Impl.AppendLn(' L, I, N : Integer;');
  1112. Impl.AppendLn('begin');
  1113. Impl.AppendLn(' P := @Buf;');
  1114. Impl.AppendLn(' L := BufSize;');
  1115. Impl.AppendLn(' I := pbDecodeValueInt32(P^, L, N);');
  1116. Impl.AppendLn(' Dec(L, I);');
  1117. Impl.AppendLn(' Inc(P, I);');
  1118. Impl.AppendLn(' pbDecodeProtoBuf(P^, N, ' + CallbackName + ', @Value);');
  1119. Impl.AppendLn(' Dec(L, N);');
  1120. Impl.AppendLn(' Result := BufSize - L;');
  1121. Impl.AppendLn('end;');
  1122. Impl.AppendLn;
  1123. Proto := 'procedure pbDecodeField' + FPascalProtoName + '(const Field: TpbProtoBufDecodeField; var Value: ' + FPascalName + ');';
  1124. Intf.AppendLn(Proto);
  1125. Impl.AppendLn(Proto);
  1126. Impl.AppendLn('begin');
  1127. Impl.AppendLn(' pbDecodeProtoBuf(Field.ValueVarBytesPtr^, Field.ValueVarBytesLen, ' + CallbackName + ', @Value);');
  1128. Impl.AppendLn('end;');
  1129. Impl.AppendLn;
  1130. end;
  1131. end;
  1132. procedure TpbProtoPascalMessage.GenerateMessageUnit(const AUnit: TCodeGenPascalUnit);
  1133. var
  1134. I : Integer;
  1135. CommentLine : AnsiString;
  1136. begin
  1137. for I := 0 to GetEnumCount - 1 do
  1138. GetPascalEnum(I).GenerateMessageUnit(AUnit);
  1139. for I := 0 to GetFieldCount - 1 do
  1140. GetPascalField(I).GenerateMessageUnit(AUnit);
  1141. for I := 0 to GetMessageCount - 1 do
  1142. GetPascalMessage(I).GenerateMessageUnit(AUnit);
  1143. CommentLine := '{ ' + FPascalName + ' }';
  1144. AUnit.Intf.AppendLn(CommentLine);
  1145. AUnit.Intf.AppendLn;
  1146. AUnit.Impl.AppendLn(CommentLine);
  1147. AUnit.Impl.AppendLn;
  1148. GenerateRecordDeclaration(AUnit);
  1149. GenerateRecordInitProc(AUnit);
  1150. GenerateRecordEncodeProc(AUnit);
  1151. GenerateRecordDecodeProc(AUnit);
  1152. AUnit.Intf.AppendLn;
  1153. AUnit.Intf.AppendLn;
  1154. AUnit.Intf.AppendLn;
  1155. AUnit.Impl.AppendLn;
  1156. AUnit.Impl.AppendLn;
  1157. end;
  1158. { TpbProtoPascalPackage }
  1159. constructor TpbProtoPascalPackage.Create;
  1160. begin
  1161. inherited Create;
  1162. FMessageUnit := TCodeGenPascalUnit.Create;
  1163. end;
  1164. destructor TpbProtoPascalPackage.Destroy;
  1165. begin
  1166. FreeAndNil(FMessageUnit);
  1167. inherited Destroy;
  1168. end;
  1169. procedure TpbProtoPascalPackage.CodeGenInit;
  1170. var
  1171. I : Integer;
  1172. begin
  1173. FPascalProtoName := ProtoNameToPascalProtoName(FName);
  1174. FPascalBaseName := 'pb' + FPascalProtoName;
  1175. FMessageUnit.Name := FPascalBaseName + 'Messages';
  1176. for I := 0 to GetImportedPackageCount - 1 do
  1177. GetPascalImportedPackage(I).CodeGenInit;
  1178. for I := 0 to GetEnumCount - 1 do
  1179. GetPascalEnum(I).CodeGenInit;
  1180. for I := 0 to GetMessageCount - 1 do
  1181. GetPascalMessage(I).CodeGenInit;
  1182. end;
  1183. procedure TpbProtoPascalPackage.GenerateMessageUnit;
  1184. var I : Integer;
  1185. begin
  1186. FMessageUnit.UnitComments := FMessageUnit.UnitComments +
  1187. '{ Unit ' + FMessageUnit.FName + '.pas }' + CRLF;
  1188. if FFileName <> '' then
  1189. FMessageUnit.UnitComments := FMessageUnit.UnitComments +
  1190. '{ Generated from ' + FFileName + ' }' + CRLF;
  1191. FMessageUnit.UnitComments := FMessageUnit.UnitComments +
  1192. '{ Package ' + FPascalProtoName + ' }' + CRLF;
  1193. FMessageUnit.IntfUses.Add('cUtils');
  1194. FMessageUnit.IntfUses.Add('cStrings');
  1195. FMessageUnit.IntfUses.Add('cProtoBufUtils');
  1196. for I := 0 to GetImportedPackageCount - 1 do
  1197. FMessageUnit.IntfUses.Add(GetPascalImportedPackage(I).FMessageUnit.FName);
  1198. for I := 0 to GetEnumCount - 1 do
  1199. GetPascalEnum(I).GenerateMessageUnit(FMessageUnit);
  1200. for I := 0 to GetMessageCount - 1 do
  1201. GetPascalMessage(I).GenerateMessageUnit(FMessageUnit);
  1202. end;
  1203. function TpbProtoPascalPackage.GetPascalMessage(const Idx: Integer): TpbProtoPascalMessage;
  1204. begin
  1205. Result := GetMessage(Idx) as TpbProtoPascalMessage;
  1206. end;
  1207. function TpbProtoPascalPackage.GetPascalEnum(const Idx: Integer): TpbProtoPascalEnum;
  1208. begin
  1209. Result := GetEnum(Idx) as TpbProtoPascalEnum;
  1210. end;
  1211. function TpbProtoPascalPackage.GetPascalImportedPackage(const Idx: Integer): TpbProtoPascalPackage;
  1212. begin
  1213. Result := GetImportedPackage(Idx) as TpbProtoPascalPackage;
  1214. end;
  1215. procedure TpbProtoPascalPackage.Save(const OutputPath: String);
  1216. begin
  1217. FMessageUnit.Save(OutputPath);
  1218. end;
  1219. { TpbProtoCodeGenPascal }
  1220. constructor TpbProtoCodeGenPascal.Create;
  1221. begin
  1222. inherited Create;
  1223. end;
  1224. destructor TpbProtoCodeGenPascal.Destroy;
  1225. begin
  1226. inherited Destroy;
  1227. end;
  1228. procedure TpbProtoCodeGenPascal.GenerateCode(const APackage: TpbProtoPackage);
  1229. var P : TpbProtoPascalPackage;
  1230. begin
  1231. Assert(Assigned(APackage));
  1232. P := (APackage as TpbProtoPascalPackage);
  1233. P.CodeGenInit;
  1234. P.GenerateMessageUnit;
  1235. P.Save(FOutputPath);
  1236. end;
  1237. { TpbProtoPascalNodeFactory }
  1238. function TpbProtoPascalNodeFactory.CreatePackage: TpbProtoPackage;
  1239. begin
  1240. Result := TpbProtoPascalPackage.Create;
  1241. end;
  1242. function TpbProtoPascalNodeFactory.CreateMessage(const AParentNode: TpbProtoNode): TpbProtoMessage;
  1243. begin
  1244. Result := TpbProtoPascalMessage.Create(AParentNode);
  1245. end;
  1246. function TpbProtoPascalNodeFactory.CreateField(const AParentMessage: TpbProtoMessage): TpbProtoField;
  1247. begin
  1248. Result := TpbProtoPascalField.Create(AParentMessage, self);
  1249. end;
  1250. function TpbProtoPascalNodeFactory.CreateFieldType(const AParentField: TpbProtoField): TpbProtoFieldType;
  1251. begin
  1252. Result := TpbProtoPascalFieldType.Create(AParentField);
  1253. end;
  1254. function TpbProtoPascalNodeFactory.CreateLiteral(const AParentNode: TpbProtoNode): TpbProtoLiteral;
  1255. begin
  1256. Result := TpbProtoPascalLiteral.Create(AParentNode);
  1257. end;
  1258. function TpbProtoPascalNodeFactory.CreateEnum(const AParentNode: TpbProtoNode): TpbProtoEnum;
  1259. begin
  1260. Result := TpbProtoPascalEnum.Create(AParentNode);
  1261. end;
  1262. function TpbProtoPascalNodeFactory.CreateEnumValue(const AParentEnum: TpbProtoEnum): TpbProtoEnumValue;
  1263. begin
  1264. Result := TpbProtoPascalEnumValue.Create(AParentEnum);
  1265. end;
  1266. { GetPascalProtoNodeFactory }
  1267. var
  1268. PascalProtoNodeFactory: TpbProtoPascalNodeFactory = nil;
  1269. function GetPascalProtoNodeFactory: TpbProtoPascalNodeFactory;
  1270. begin
  1271. if not Assigned(PascalProtoNodeFactory) then
  1272. PascalProtoNodeFactory := TpbProtoPascalNodeFactory.Create;
  1273. Result := PascalProtoNodeFactory;
  1274. end;
  1275. end.