paswrite.pp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622
  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. case AClass.ObjKind of
  181. okObject: wrt('object');
  182. okClass: wrt('class');
  183. okInterface: wrt('interface');
  184. end;
  185. if Assigned(AClass.AncestorType) then
  186. wrtln('(' + AClass.AncestorType.Name + ')')
  187. else
  188. wrtln;
  189. IncIndent;
  190. LastVisibility := visDefault;
  191. for i := 0 to AClass.Members.Count - 1 do
  192. begin
  193. Member := TPasElement(AClass.Members[i]);
  194. CurVisibility := Member.Visibility;
  195. if CurVisibility <> LastVisibility then
  196. begin
  197. DecIndent;
  198. case CurVisibility of
  199. visPrivate: wrtln('private');
  200. visProtected: wrtln('protected');
  201. visPublic: wrtln('public');
  202. visPublished: wrtln('published');
  203. visAutomated: wrtln('automated');
  204. end;
  205. IncIndent;
  206. LastVisibility := CurVisibility;
  207. end;
  208. WriteElement(Member);
  209. end;
  210. DecIndent;
  211. wrtln('end;');
  212. wrtln;
  213. end;
  214. procedure TPasWriter.WriteVariable(AVar: TPasVariable);
  215. begin
  216. if (AVar.Parent.ClassType <> TPasClassType) and
  217. (AVar.Parent.ClassType <> TPasRecordType) then
  218. PrepareDeclSection('var');
  219. wrt(AVar.Name + ': ');
  220. WriteType(AVar.VarType);
  221. wrtln(';');
  222. end;
  223. procedure TPasWriter.WriteProcDecl(AProc: TPasProcedure);
  224. var
  225. i: Integer;
  226. begin
  227. wrt(AProc.TypeName + ' ' + AProc.Name);
  228. if Assigned(AProc.ProcType) and (AProc.ProcType.Args.Count > 0) then
  229. begin
  230. wrt('(');
  231. for i := 0 to AProc.ProcType.Args.Count - 1 do
  232. with TPasArgument(AProc.ProcType.Args[i]) do
  233. begin
  234. if i > 0 then
  235. wrt('; ');
  236. case Access of
  237. argConst: wrt('const ');
  238. argVar: wrt('var ');
  239. end;
  240. wrt(Name);
  241. if Assigned(ArgType) then
  242. begin
  243. wrt(': ');
  244. WriteElement(ArgType);
  245. end;
  246. if Value <> '' then
  247. wrt(' = ' + Value);
  248. end;
  249. wrt(')');
  250. end;
  251. if Assigned(AProc.ProcType) and
  252. (AProc.ProcType.ClassType = TPasFunctionType) then
  253. begin
  254. wrt(': ');
  255. WriteElement(TPasFunctionType(AProc.ProcType).ResultEl.ResultType);
  256. end;
  257. wrt(';');
  258. if AProc.IsVirtual then
  259. wrt(' virtual;');
  260. if AProc.IsDynamic then
  261. wrt(' dynamic;');
  262. if AProc.IsAbstract then
  263. wrt(' abstract;');
  264. if AProc.IsOverride then
  265. wrt(' override;');
  266. if AProc.IsOverload then
  267. wrt(' overload;');
  268. // !!!: Not handled: Message, calling conventions
  269. wrtln;
  270. end;
  271. procedure TPasWriter.WriteProcImpl(AProc: TPasProcedureImpl);
  272. var
  273. i: Integer;
  274. begin
  275. PrepareDeclSection('');
  276. wrt(AProc.TypeName + ' ');
  277. if AProc.Parent.ClassType = TPasClassType then
  278. wrt(AProc.Parent.Name + '.');
  279. wrt(AProc.Name);
  280. if Assigned(AProc.ProcType) and (AProc.ProcType.Args.Count > 0) then
  281. begin
  282. wrt('(');
  283. for i := 0 to AProc.ProcType.Args.Count - 1 do
  284. with TPasArgument(AProc.ProcType.Args[i]) do
  285. begin
  286. if i > 0 then
  287. wrt('; ');
  288. case Access of
  289. argConst: wrt('const ');
  290. argVar: wrt('var ');
  291. end;
  292. wrt(Name);
  293. if Assigned(ArgType) then
  294. begin
  295. wrt(': ');
  296. WriteElement(ArgType);
  297. end;
  298. if Value <> '' then
  299. wrt(' = ' + Value);
  300. end;
  301. wrt(')');
  302. end;
  303. if Assigned(AProc.ProcType) and
  304. (AProc.ProcType.ClassType = TPasFunctionType) then
  305. begin
  306. wrt(': ');
  307. WriteElement(TPasFunctionType(AProc.ProcType).ResultEl.ResultType);
  308. end;
  309. wrtln(';');
  310. IncDeclSectionLevel;
  311. for i := 0 to AProc.Locals.Count - 1 do
  312. begin
  313. if TPasElement(AProc.Locals[i]).InheritsFrom(TPasProcedureImpl) then
  314. begin
  315. IncIndent;
  316. if (i = 0) or not
  317. TPasElement(AProc.Locals[i - 1]).InheritsFrom(TPasProcedureImpl) then
  318. wrtln;
  319. end;
  320. WriteElement(TPasElement(AProc.Locals[i]));
  321. if TPasElement(AProc.Locals[i]).InheritsFrom(TPasProcedureImpl) then
  322. DecIndent;
  323. end;
  324. DecDeclSectionLevel;
  325. wrtln('begin');
  326. IncIndent;
  327. if Assigned(AProc.Body) then
  328. WriteImplBlock(AProc.Body);
  329. DecIndent;
  330. wrtln('end;');
  331. wrtln;
  332. end;
  333. procedure TPasWriter.WriteProperty(AProp: TPasProperty);
  334. var
  335. i: Integer;
  336. begin
  337. wrt('property ' + AProp.Name);
  338. if AProp.Args.Count > 0 then
  339. begin
  340. wrt('[');
  341. for i := 0 to AProp.Args.Count - 1 do;
  342. // !!!: Create WriteArgument method and call it here
  343. wrt(']');
  344. end;
  345. if Assigned(AProp.VarType) then
  346. begin
  347. wrt(': ');
  348. WriteType(AProp.VarType);
  349. end;
  350. if AProp.ReadAccessorName <> '' then
  351. wrt(' read ' + AProp.ReadAccessorName);
  352. if AProp.WriteAccessorName <> '' then
  353. wrt(' write ' + AProp.WriteAccessorName);
  354. if AProp.StoredAccessorName <> '' then
  355. wrt(' stored ' + AProp.StoredAccessorName);
  356. if AProp.DefaultValue <> '' then
  357. wrt(' default ' + AProp.DefaultValue);
  358. if AProp.IsNodefault then
  359. wrt(' nodefault');
  360. if AProp.IsDefault then
  361. wrt('; default');
  362. wrtln(';');
  363. end;
  364. procedure TPasWriter.WriteImplBlock(ABlock: TPasImplBlock);
  365. var
  366. i: Integer;
  367. begin
  368. for i := 0 to ABlock.Elements.Count - 1 do
  369. begin
  370. WriteImplElement(TPasImplElement(ABlock.Elements[i]), False);
  371. if TPasImplElement(ABlock.Elements[i]).ClassType = TPasImplCommand then
  372. wrtln(';');
  373. end;
  374. end;
  375. procedure TPasWriter.WriteImplElement(AElement: TPasImplElement;
  376. AAutoInsertBeginEnd: Boolean);
  377. begin
  378. if AElement.ClassType = TPasImplCommand then
  379. WriteImplCommand(TPasImplCommand(AElement))
  380. else if AElement.ClassType = TPasImplCommands then
  381. begin
  382. DecIndent;
  383. if AAutoInsertBeginEnd then
  384. wrtln('begin');
  385. IncIndent;
  386. WriteImplCommands(TPasImplCommands(AElement));
  387. DecIndent;
  388. if AAutoInsertBeginEnd then
  389. wrtln('end;');
  390. IncIndent;
  391. end else if AElement.ClassType = TPasImplBlock then
  392. begin
  393. DecIndent;
  394. if AAutoInsertBeginEnd then
  395. wrtln('begin');
  396. IncIndent;
  397. WriteImplBlock(TPasImplBlock(AElement));
  398. DecIndent;
  399. if AAutoInsertBeginEnd then
  400. wrtln('end;');
  401. IncIndent;
  402. end else if AElement.ClassType = TPasImplIfElse then
  403. WriteImplIfElse(TPasImplIfElse(AElement))
  404. else if AElement.ClassType = TPasImplForLoop then
  405. WriteImplForLoop(TPasImplForLoop(AElement))
  406. else
  407. raise Exception.Create('Writing not yet implemented for ' +
  408. AElement.ClassName + ' implementation elements');
  409. end;
  410. procedure TPasWriter.WriteImplCommand(ACommand: TPasImplCommand);
  411. begin
  412. wrt(ACommand.Command);
  413. end;
  414. procedure TPasWriter.WriteImplCommands(ACommands: TPasImplCommands);
  415. var
  416. i: Integer;
  417. s: String;
  418. begin
  419. for i := 0 to ACommands.Commands.Count - 1 do
  420. begin
  421. s := ACommands.Commands[i];
  422. if Length(s) > 0 then
  423. if (Length(s) >= 2) and (s[1] = '/') and (s[2] = '/') then
  424. wrtln(s)
  425. else
  426. wrtln(s + ';');
  427. end;
  428. end;
  429. procedure TPasWriter.WriteImplIfElse(AIfElse: TPasImplIfElse);
  430. begin
  431. wrt('if ' + AIfElse.Condition + ' then');
  432. if Assigned(AIfElse.IfBranch) then
  433. begin
  434. wrtln;
  435. if (AIfElse.IfBranch.ClassType = TPasImplCommands) or
  436. (AIfElse.IfBranch.ClassType = TPasImplBlock) then
  437. wrtln('begin');
  438. IncIndent;
  439. WriteImplElement(AIfElse.IfBranch, False);
  440. DecIndent;
  441. if (AIfElse.IfBranch.ClassType = TPasImplCommands) or
  442. (AIfElse.IfBranch.ClassType = TPasImplBlock) then
  443. if Assigned(AIfElse.ElseBranch) then
  444. wrt('end ')
  445. else
  446. wrtln('end;')
  447. else
  448. if Assigned(AIfElse.ElseBranch) then
  449. wrtln;
  450. end else
  451. if not Assigned(AIfElse.ElseBranch) then
  452. wrtln(';')
  453. else
  454. wrtln;
  455. if Assigned(AIfElse.ElseBranch) then
  456. if AIfElse.ElseBranch.ClassType = TPasImplIfElse then
  457. begin
  458. wrt('else ');
  459. WriteImplElement(AIfElse.ElseBranch, True);
  460. end else
  461. begin
  462. wrtln('else');
  463. IncIndent;
  464. WriteImplElement(AIfElse.ElseBranch, True);
  465. if (not Assigned(AIfElse.Parent)) or
  466. (AIfElse.Parent.ClassType <> TPasImplIfElse) or
  467. (TPasImplIfElse(AIfElse.Parent).IfBranch <> AIfElse) then
  468. wrtln(';');
  469. DecIndent;
  470. end;
  471. end;
  472. procedure TPasWriter.WriteImplForLoop(AForLoop: TPasImplForLoop);
  473. begin
  474. wrtln('for ' + AForLoop.Variable.Name + ' := ' + AForLoop.StartValue +
  475. ' to ' + AForLoop.EndValue + ' do');
  476. IncIndent;
  477. WriteImplElement(AForLoop.Body, True);
  478. DecIndent;
  479. if (AForLoop.Body.ClassType <> TPasImplBlock) and
  480. (AForLoop.Body.ClassType <> TPasImplCommands) then
  481. wrtln(';');
  482. end;
  483. procedure TPasWriter.IncIndent;
  484. begin
  485. Indent := Indent + ' ';
  486. end;
  487. procedure TPasWriter.DecIndent;
  488. begin
  489. if Indent = '' then
  490. raise Exception.Create('Internal indent error');
  491. SetLength(Indent, Length(Indent) - 2);
  492. end;
  493. procedure TPasWriter.IncDeclSectionLevel;
  494. var
  495. El: PDeclSectionStackElement;
  496. begin
  497. New(El);
  498. DeclSectionStack.Add(El);
  499. El^.LastDeclSection := CurDeclSection;
  500. El^.LastIndent := Indent;
  501. CurDeclSection := '';
  502. end;
  503. procedure TPasWriter.DecDeclSectionLevel;
  504. var
  505. El: PDeclSectionStackElement;
  506. begin
  507. El := PDeclSectionStackElement(DeclSectionStack[DeclSectionStack.Count - 1]);
  508. DeclSectionStack.Delete(DeclSectionStack.Count - 1);
  509. CurDeclSection := El^.LastDeclSection;
  510. Indent := El^.LastIndent;
  511. Dispose(El);
  512. end;
  513. procedure TPasWriter.PrepareDeclSection(const ADeclSection: String);
  514. begin
  515. if ADeclSection <> CurDeclSection then
  516. begin
  517. if CurDeclsection <> '' then
  518. DecIndent;
  519. if ADeclSection <> '' then
  520. begin
  521. wrtln(ADeclSection);
  522. IncIndent;
  523. end;
  524. CurDeclSection := ADeclSection;
  525. end;
  526. end;
  527. procedure WritePasFile(AElement: TPasElement; const AFilename: String);
  528. var
  529. Stream: TFileStream;
  530. begin
  531. Stream := TFileStream.Create(AFilename, fmCreate);
  532. try
  533. WritePasFile(AElement, Stream);
  534. finally
  535. Stream.Free;
  536. end;
  537. end;
  538. procedure WritePasFile(AElement: TPasElement; AStream: TStream);
  539. var
  540. Writer: TPasWriter;
  541. begin
  542. Writer := TPasWriter.Create(AStream);
  543. try
  544. Writer.WriteElement(AElement);
  545. finally
  546. Writer.Free;
  547. end;
  548. end;
  549. end.
  550. {
  551. $Log$
  552. Revision 1.1 2003-03-13 21:47:42 sg
  553. * First version as part of FCL
  554. }