paswrite.pp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624
  1. {
  2. $Id$
  3. This file is part of the Free Component Library
  4. Pascal tree source file writer
  5. Copyright (c) 2003 by
  6. Areca Systems GmbH / Sebastian Guenther, [email protected]
  7. See the file COPYING.FPC, included in this distribution,
  8. for details about the copyright.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. **********************************************************************}
  13. unit PasWrite;
  14. interface
  15. uses Classes, PasTree;
  16. type
  17. TPasWriter = class
  18. private
  19. FStream: TStream;
  20. IsStartOfLine: Boolean;
  21. Indent, CurDeclSection: String;
  22. DeclSectionStack: TList;
  23. procedure IncIndent;
  24. procedure DecIndent;
  25. procedure IncDeclSectionLevel;
  26. procedure DecDeclSectionLevel;
  27. procedure PrepareDeclSection(const ADeclSection: String);
  28. public
  29. constructor Create(AStream: TStream);
  30. destructor Destroy; override;
  31. procedure wrt(const s: String);
  32. procedure wrtln(const s: String);
  33. procedure wrtln;
  34. procedure WriteElement(AElement: TPasElement);
  35. procedure WriteType(AType: TPasType);
  36. procedure WriteModule(AModule: TPasModule);
  37. procedure WriteSection(ASection: TPasSection);
  38. procedure WriteClass(AClass: TPasClassType);
  39. procedure WriteVariable(AVar: TPasVariable);
  40. procedure WriteProcDecl(AProc: TPasProcedure);
  41. procedure WriteProcImpl(AProc: TPasProcedureImpl);
  42. procedure WriteProperty(AProp: TPasProperty);
  43. procedure WriteImplBlock(ABlock: TPasImplBlock);
  44. procedure WriteImplElement(AElement: TPasImplElement;
  45. AAutoInsertBeginEnd: Boolean);
  46. procedure WriteImplCommand(ACommand: TPasImplCommand);
  47. procedure WriteImplCommands(ACommands: TPasImplCommands);
  48. procedure WriteImplIfElse(AIfElse: TPasImplIfElse);
  49. procedure WriteImplForLoop(AForLoop: TPasImplForLoop);
  50. property Stream: TStream read FStream;
  51. end;
  52. procedure WritePasFile(AElement: TPasElement; const AFilename: String);
  53. procedure WritePasFile(AElement: TPasElement; AStream: TStream);
  54. implementation
  55. uses SysUtils;
  56. type
  57. PDeclSectionStackElement = ^TDeclSectionStackElement;
  58. TDeclSectionStackElement = record
  59. LastDeclSection, LastIndent: String;
  60. end;
  61. constructor TPasWriter.Create(AStream: TStream);
  62. begin
  63. FStream := AStream;
  64. IsStartOfLine := True;
  65. DeclSectionStack := TList.Create;
  66. end;
  67. destructor TPasWriter.Destroy;
  68. var
  69. i: Integer;
  70. El: PDeclSectionStackElement;
  71. begin
  72. for i := 0 to DeclSectionStack.Count - 1 do
  73. begin
  74. El := PDeclSectionStackElement(DeclSectionStack[i]);
  75. Dispose(El);
  76. end;
  77. DeclSectionStack.Free;
  78. inherited Destroy;
  79. end;
  80. procedure TPasWriter.wrt(const s: String);
  81. begin
  82. if IsStartOfLine then
  83. begin
  84. if Length(Indent) > 0 then
  85. Stream.Write(Indent[1], Length(Indent));
  86. IsStartOfLine := False;
  87. end;
  88. Stream.Write(s[1], Length(s));
  89. end;
  90. const
  91. LF: String = #10;
  92. procedure TPasWriter.wrtln(const s: String);
  93. begin
  94. wrt(s);
  95. Stream.Write(LF[1], 1);
  96. IsStartOfLine := True;
  97. end;
  98. procedure TPasWriter.wrtln;
  99. begin
  100. Stream.Write(LF[1], 1);
  101. IsStartOfLine := True;
  102. end;
  103. procedure TPasWriter.WriteElement(AElement: TPasElement);
  104. begin
  105. if AElement.ClassType = TPasModule then
  106. WriteModule(TPasModule(AElement))
  107. else if AElement.ClassType = TPasSection then
  108. WriteSection(TPasSection(AElement))
  109. else if AElement.ClassType = TPasVariable then
  110. WriteVariable(TPasVariable(AElement))
  111. else if AElement.InheritsFrom(TPasType) then
  112. WriteType(TPasType(AElement))
  113. else if AElement.InheritsFrom(TPasProcedure) then
  114. WriteProcDecl(TPasProcedure(AElement))
  115. else if AElement.InheritsFrom(TPasProcedureImpl) then
  116. WriteProcImpl(TPasProcedureImpl(AElement))
  117. else if AElement.ClassType = TPasProperty then
  118. WriteProperty(TPasProperty(AElement))
  119. else
  120. raise Exception.Create('Writing not implemented for ' +
  121. AElement.ElementTypeName + ' nodes');
  122. end;
  123. procedure TPasWriter.WriteType(AType: TPasType);
  124. begin
  125. if AType.ClassType = TPasUnresolvedTypeRef then
  126. wrt(AType.Name)
  127. else if AType.ClassType = TPasClassType then
  128. WriteClass(TPasClassType(AType))
  129. else
  130. raise Exception.Create('Writing not implemented for ' +
  131. AType.ElementTypeName + ' nodes');
  132. end;
  133. procedure TPasWriter.WriteModule(AModule: TPasModule);
  134. begin
  135. wrtln('unit ' + AModule.Name + ';');
  136. wrtln;
  137. wrtln('interface');
  138. wrtln;
  139. WriteSection(AModule.InterfaceSection);
  140. Indent := '';
  141. wrtln;
  142. wrtln;
  143. wrtln('implementation');
  144. if Assigned(AModule.ImplementationSection) then
  145. begin
  146. wrtln;
  147. WriteSection(AModule.ImplementationSection);
  148. end;
  149. wrtln;
  150. wrtln('end.');
  151. end;
  152. procedure TPasWriter.WriteSection(ASection: TPasSection);
  153. var
  154. i: Integer;
  155. begin
  156. if ASection.UsesList.Count > 0 then
  157. begin
  158. wrt('uses ');
  159. for i := 0 to ASection.UsesList.Count - 1 do
  160. begin
  161. if i > 0 then
  162. wrt(', ');
  163. wrt(TPasElement(ASection.UsesList[i]).Name);
  164. end;
  165. wrtln(';');
  166. wrtln;
  167. end;
  168. CurDeclSection := '';
  169. for i := 0 to ASection.Declarations.Count - 1 do
  170. WriteElement(TPasElement(ASection.Declarations[i]));
  171. end;
  172. procedure TPasWriter.WriteClass(AClass: TPasClassType);
  173. var
  174. i: Integer;
  175. Member: TPasElement;
  176. LastVisibility, CurVisibility: TPasMemberVisibility;
  177. begin
  178. PrepareDeclSection('type');
  179. wrt(AClass.Name + ' = ');
  180. if AClass.IsPacked then
  181. wrt('packed '); // 12/04/04 - Dave - Added
  182. case AClass.ObjKind of
  183. okObject: wrt('object');
  184. okClass: wrt('class');
  185. okInterface: wrt('interface');
  186. end;
  187. if Assigned(AClass.AncestorType) then
  188. wrtln('(' + AClass.AncestorType.Name + ')')
  189. else
  190. wrtln;
  191. IncIndent;
  192. LastVisibility := visDefault;
  193. for i := 0 to AClass.Members.Count - 1 do
  194. begin
  195. Member := TPasElement(AClass.Members[i]);
  196. CurVisibility := Member.Visibility;
  197. if CurVisibility <> LastVisibility then
  198. begin
  199. DecIndent;
  200. case CurVisibility of
  201. visPrivate: wrtln('private');
  202. visProtected: wrtln('protected');
  203. visPublic: wrtln('public');
  204. visPublished: wrtln('published');
  205. visAutomated: wrtln('automated');
  206. end;
  207. IncIndent;
  208. LastVisibility := CurVisibility;
  209. end;
  210. WriteElement(Member);
  211. end;
  212. DecIndent;
  213. wrtln('end;');
  214. wrtln;
  215. end;
  216. procedure TPasWriter.WriteVariable(AVar: TPasVariable);
  217. begin
  218. if (AVar.Parent.ClassType <> TPasClassType) and
  219. (AVar.Parent.ClassType <> TPasRecordType) then
  220. PrepareDeclSection('var');
  221. wrt(AVar.Name + ': ');
  222. WriteType(AVar.VarType);
  223. wrtln(';');
  224. end;
  225. procedure TPasWriter.WriteProcDecl(AProc: TPasProcedure);
  226. var
  227. i: Integer;
  228. begin
  229. wrt(AProc.TypeName + ' ' + AProc.Name);
  230. if Assigned(AProc.ProcType) and (AProc.ProcType.Args.Count > 0) then
  231. begin
  232. wrt('(');
  233. for i := 0 to AProc.ProcType.Args.Count - 1 do
  234. with TPasArgument(AProc.ProcType.Args[i]) do
  235. begin
  236. if i > 0 then
  237. wrt('; ');
  238. case Access of
  239. argConst: wrt('const ');
  240. argVar: wrt('var ');
  241. end;
  242. wrt(Name);
  243. if Assigned(ArgType) then
  244. begin
  245. wrt(': ');
  246. WriteElement(ArgType);
  247. end;
  248. if Value <> '' then
  249. wrt(' = ' + Value);
  250. end;
  251. wrt(')');
  252. end;
  253. if Assigned(AProc.ProcType) and
  254. (AProc.ProcType.ClassType = TPasFunctionType) then
  255. begin
  256. wrt(': ');
  257. WriteElement(TPasFunctionType(AProc.ProcType).ResultEl.ResultType);
  258. end;
  259. wrt(';');
  260. if AProc.IsVirtual then
  261. wrt(' virtual;');
  262. if AProc.IsDynamic then
  263. wrt(' dynamic;');
  264. if AProc.IsAbstract then
  265. wrt(' abstract;');
  266. if AProc.IsOverride then
  267. wrt(' override;');
  268. if AProc.IsOverload then
  269. wrt(' overload;');
  270. // !!!: Not handled: Message, calling conventions
  271. wrtln;
  272. end;
  273. procedure TPasWriter.WriteProcImpl(AProc: TPasProcedureImpl);
  274. var
  275. i: Integer;
  276. begin
  277. PrepareDeclSection('');
  278. wrt(AProc.TypeName + ' ');
  279. if AProc.Parent.ClassType = TPasClassType then
  280. wrt(AProc.Parent.Name + '.');
  281. wrt(AProc.Name);
  282. if Assigned(AProc.ProcType) and (AProc.ProcType.Args.Count > 0) then
  283. begin
  284. wrt('(');
  285. for i := 0 to AProc.ProcType.Args.Count - 1 do
  286. with TPasArgument(AProc.ProcType.Args[i]) do
  287. begin
  288. if i > 0 then
  289. wrt('; ');
  290. case Access of
  291. argConst: wrt('const ');
  292. argVar: wrt('var ');
  293. end;
  294. wrt(Name);
  295. if Assigned(ArgType) then
  296. begin
  297. wrt(': ');
  298. WriteElement(ArgType);
  299. end;
  300. if Value <> '' then
  301. wrt(' = ' + Value);
  302. end;
  303. wrt(')');
  304. end;
  305. if Assigned(AProc.ProcType) and
  306. (AProc.ProcType.ClassType = TPasFunctionType) then
  307. begin
  308. wrt(': ');
  309. WriteElement(TPasFunctionType(AProc.ProcType).ResultEl.ResultType);
  310. end;
  311. wrtln(';');
  312. IncDeclSectionLevel;
  313. for i := 0 to AProc.Locals.Count - 1 do
  314. begin
  315. if TPasElement(AProc.Locals[i]).InheritsFrom(TPasProcedureImpl) then
  316. begin
  317. IncIndent;
  318. if (i = 0) or not
  319. TPasElement(AProc.Locals[i - 1]).InheritsFrom(TPasProcedureImpl) then
  320. wrtln;
  321. end;
  322. WriteElement(TPasElement(AProc.Locals[i]));
  323. if TPasElement(AProc.Locals[i]).InheritsFrom(TPasProcedureImpl) then
  324. DecIndent;
  325. end;
  326. DecDeclSectionLevel;
  327. wrtln('begin');
  328. IncIndent;
  329. if Assigned(AProc.Body) then
  330. WriteImplBlock(AProc.Body);
  331. DecIndent;
  332. wrtln('end;');
  333. wrtln;
  334. end;
  335. procedure TPasWriter.WriteProperty(AProp: TPasProperty);
  336. var
  337. i: Integer;
  338. begin
  339. wrt('property ' + AProp.Name);
  340. if AProp.Args.Count > 0 then
  341. begin
  342. wrt('[');
  343. for i := 0 to AProp.Args.Count - 1 do;
  344. // !!!: Create WriteArgument method and call it here
  345. wrt(']');
  346. end;
  347. if Assigned(AProp.VarType) then
  348. begin
  349. wrt(': ');
  350. WriteType(AProp.VarType);
  351. end;
  352. if AProp.ReadAccessorName <> '' then
  353. wrt(' read ' + AProp.ReadAccessorName);
  354. if AProp.WriteAccessorName <> '' then
  355. wrt(' write ' + AProp.WriteAccessorName);
  356. if AProp.StoredAccessorName <> '' then
  357. wrt(' stored ' + AProp.StoredAccessorName);
  358. if AProp.DefaultValue <> '' then
  359. wrt(' default ' + AProp.DefaultValue);
  360. if AProp.IsNodefault then
  361. wrt(' nodefault');
  362. if AProp.IsDefault then
  363. wrt('; default');
  364. wrtln(';');
  365. end;
  366. procedure TPasWriter.WriteImplBlock(ABlock: TPasImplBlock);
  367. var
  368. i: Integer;
  369. begin
  370. for i := 0 to ABlock.Elements.Count - 1 do
  371. begin
  372. WriteImplElement(TPasImplElement(ABlock.Elements[i]), False);
  373. if TPasImplElement(ABlock.Elements[i]).ClassType = TPasImplCommand then
  374. wrtln(';');
  375. end;
  376. end;
  377. procedure TPasWriter.WriteImplElement(AElement: TPasImplElement;
  378. AAutoInsertBeginEnd: Boolean);
  379. begin
  380. if AElement.ClassType = TPasImplCommand then
  381. WriteImplCommand(TPasImplCommand(AElement))
  382. else if AElement.ClassType = TPasImplCommands then
  383. begin
  384. DecIndent;
  385. if AAutoInsertBeginEnd then
  386. wrtln('begin');
  387. IncIndent;
  388. WriteImplCommands(TPasImplCommands(AElement));
  389. DecIndent;
  390. if AAutoInsertBeginEnd then
  391. wrtln('end;');
  392. IncIndent;
  393. end else if AElement.ClassType = TPasImplBlock then
  394. begin
  395. DecIndent;
  396. if AAutoInsertBeginEnd then
  397. wrtln('begin');
  398. IncIndent;
  399. WriteImplBlock(TPasImplBlock(AElement));
  400. DecIndent;
  401. if AAutoInsertBeginEnd then
  402. wrtln('end;');
  403. IncIndent;
  404. end else if AElement.ClassType = TPasImplIfElse then
  405. WriteImplIfElse(TPasImplIfElse(AElement))
  406. else if AElement.ClassType = TPasImplForLoop then
  407. WriteImplForLoop(TPasImplForLoop(AElement))
  408. else
  409. raise Exception.Create('Writing not yet implemented for ' +
  410. AElement.ClassName + ' implementation elements');
  411. end;
  412. procedure TPasWriter.WriteImplCommand(ACommand: TPasImplCommand);
  413. begin
  414. wrt(ACommand.Command);
  415. end;
  416. procedure TPasWriter.WriteImplCommands(ACommands: TPasImplCommands);
  417. var
  418. i: Integer;
  419. s: String;
  420. begin
  421. for i := 0 to ACommands.Commands.Count - 1 do
  422. begin
  423. s := ACommands.Commands[i];
  424. if Length(s) > 0 then
  425. if (Length(s) >= 2) and (s[1] = '/') and (s[2] = '/') then
  426. wrtln(s)
  427. else
  428. wrtln(s + ';');
  429. end;
  430. end;
  431. procedure TPasWriter.WriteImplIfElse(AIfElse: TPasImplIfElse);
  432. begin
  433. wrt('if ' + AIfElse.Condition + ' then');
  434. if Assigned(AIfElse.IfBranch) then
  435. begin
  436. wrtln;
  437. if (AIfElse.IfBranch.ClassType = TPasImplCommands) or
  438. (AIfElse.IfBranch.ClassType = TPasImplBlock) then
  439. wrtln('begin');
  440. IncIndent;
  441. WriteImplElement(AIfElse.IfBranch, False);
  442. DecIndent;
  443. if (AIfElse.IfBranch.ClassType = TPasImplCommands) or
  444. (AIfElse.IfBranch.ClassType = TPasImplBlock) then
  445. if Assigned(AIfElse.ElseBranch) then
  446. wrt('end ')
  447. else
  448. wrtln('end;')
  449. else
  450. if Assigned(AIfElse.ElseBranch) then
  451. wrtln;
  452. end else
  453. if not Assigned(AIfElse.ElseBranch) then
  454. wrtln(';')
  455. else
  456. wrtln;
  457. if Assigned(AIfElse.ElseBranch) then
  458. if AIfElse.ElseBranch.ClassType = TPasImplIfElse then
  459. begin
  460. wrt('else ');
  461. WriteImplElement(AIfElse.ElseBranch, True);
  462. end else
  463. begin
  464. wrtln('else');
  465. IncIndent;
  466. WriteImplElement(AIfElse.ElseBranch, True);
  467. if (not Assigned(AIfElse.Parent)) or
  468. (AIfElse.Parent.ClassType <> TPasImplIfElse) or
  469. (TPasImplIfElse(AIfElse.Parent).IfBranch <> AIfElse) then
  470. wrtln(';');
  471. DecIndent;
  472. end;
  473. end;
  474. procedure TPasWriter.WriteImplForLoop(AForLoop: TPasImplForLoop);
  475. begin
  476. wrtln('for ' + AForLoop.Variable.Name + ' := ' + AForLoop.StartValue +
  477. ' to ' + AForLoop.EndValue + ' do');
  478. IncIndent;
  479. WriteImplElement(AForLoop.Body, True);
  480. DecIndent;
  481. if (AForLoop.Body.ClassType <> TPasImplBlock) and
  482. (AForLoop.Body.ClassType <> TPasImplCommands) then
  483. wrtln(';');
  484. end;
  485. procedure TPasWriter.IncIndent;
  486. begin
  487. Indent := Indent + ' ';
  488. end;
  489. procedure TPasWriter.DecIndent;
  490. begin
  491. if Indent = '' then
  492. raise Exception.Create('Internal indent error');
  493. SetLength(Indent, Length(Indent) - 2);
  494. end;
  495. procedure TPasWriter.IncDeclSectionLevel;
  496. var
  497. El: PDeclSectionStackElement;
  498. begin
  499. New(El);
  500. DeclSectionStack.Add(El);
  501. El^.LastDeclSection := CurDeclSection;
  502. El^.LastIndent := Indent;
  503. CurDeclSection := '';
  504. end;
  505. procedure TPasWriter.DecDeclSectionLevel;
  506. var
  507. El: PDeclSectionStackElement;
  508. begin
  509. El := PDeclSectionStackElement(DeclSectionStack[DeclSectionStack.Count - 1]);
  510. DeclSectionStack.Delete(DeclSectionStack.Count - 1);
  511. CurDeclSection := El^.LastDeclSection;
  512. Indent := El^.LastIndent;
  513. Dispose(El);
  514. end;
  515. procedure TPasWriter.PrepareDeclSection(const ADeclSection: String);
  516. begin
  517. if ADeclSection <> CurDeclSection then
  518. begin
  519. if CurDeclsection <> '' then
  520. DecIndent;
  521. if ADeclSection <> '' then
  522. begin
  523. wrtln(ADeclSection);
  524. IncIndent;
  525. end;
  526. CurDeclSection := ADeclSection;
  527. end;
  528. end;
  529. procedure WritePasFile(AElement: TPasElement; const AFilename: String);
  530. var
  531. Stream: TFileStream;
  532. begin
  533. Stream := TFileStream.Create(AFilename, fmCreate);
  534. try
  535. WritePasFile(AElement, Stream);
  536. finally
  537. Stream.Free;
  538. end;
  539. end;
  540. procedure WritePasFile(AElement: TPasElement; AStream: TStream);
  541. var
  542. Writer: TPasWriter;
  543. begin
  544. Writer := TPasWriter.Create(AStream);
  545. try
  546. Writer.WriteElement(AElement);
  547. finally
  548. Writer.Free;
  549. end;
  550. end;
  551. end.
  552. {
  553. $Log$
  554. Revision 1.3 2005-02-14 17:13:16 peter
  555. * truncate log
  556. }