mkxmlrpc.pp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773
  1. {
  2. $Id$
  3. Automatic XML-RPC wrapper generator
  4. Copyright (c) 2003 by
  5. Areca Systems GmbH / Sebastian Guenther, [email protected]
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. }
  12. program MkXMLRPC;
  13. uses SysUtils, Classes, PParser, PasTree, PasWrite;
  14. resourcestring
  15. SCmdLineInvalidOption = 'Ignoring unknown option "%s"';
  16. SNoServerClassNameProvided =
  17. 'No server class name provided (use --serverclass=<name>)';
  18. SNoUnitNameProvided =
  19. 'No name for generated unit provided (use --unitname=<name>)';
  20. type
  21. TParserEngine = class(TPasTreeContainer)
  22. protected
  23. CurModule: TPasModule;
  24. public
  25. function CreateElement(AClass: TPTreeElement; const AName: String;
  26. AParent: TPasElement; AVisibility: TPasMemberVisibility): TPasElement;
  27. override;
  28. function FindElement(const AName: String): TPasElement; override;
  29. { function FindModule(const AName: String): TPasModule; override;}
  30. end;
  31. TServerClass = class
  32. Element: TPasClassType;
  33. ImplName: String;
  34. end;
  35. TRPCList = class
  36. constructor Create;
  37. destructor Destroy; override;
  38. procedure AddServerClass(const AClassName: String);
  39. ServerClasses: TList;
  40. UsedModules: TStringList;
  41. end;
  42. var
  43. Engine: TParserEngine;
  44. function TParserEngine.CreateElement(AClass: TPTreeElement; const AName: String;
  45. AParent: TPasElement; AVisibility: TPasMemberVisibility): TPasElement;
  46. begin
  47. Result := AClass.Create(AName, AParent);
  48. Result.Visibility := AVisibility;
  49. if AClass.InheritsFrom(TPasModule) then
  50. CurModule := TPasModule(Result);
  51. end;
  52. function TParserEngine.FindElement(const AName: String): TPasElement;
  53. function FindInModule(AModule: TPasModule; const LocalName: String): TPasElement;
  54. var
  55. l: TList;
  56. i: Integer;
  57. begin
  58. l := AModule.InterfaceSection.Declarations;
  59. for i := 0 to l.Count - 1 do
  60. begin
  61. Result := TPasElement(l[i]);
  62. if CompareText(Result.Name, LocalName) = 0 then
  63. exit;
  64. end;
  65. Result := nil;
  66. end;
  67. var
  68. i: Integer;
  69. //ModuleName, LocalName: String;
  70. Module: TPasElement;
  71. begin
  72. {!!!: Don't know if we ever will have to use the following:
  73. i := Pos('.', AName);
  74. if i <> 0 then
  75. begin
  76. WriteLn('Dot found in name: ', AName);
  77. Result := nil;
  78. end else
  79. begin}
  80. Result := FindInModule(CurModule, AName);
  81. if not Assigned(Result) then
  82. for i := CurModule.InterfaceSection.UsesList.Count - 1 downto 0 do
  83. begin
  84. Module := TPasElement(CurModule.InterfaceSection.UsesList[i]);
  85. if Module.ClassType = TPasModule then
  86. begin
  87. Result := FindInModule(TPasModule(Module), AName);
  88. if Assigned(Result) then
  89. exit;
  90. end;
  91. end;
  92. {end;}
  93. end;
  94. constructor TRPCList.Create;
  95. begin
  96. ServerClasses := TList.Create;
  97. UsedModules := TStringList.Create;
  98. end;
  99. destructor TRPCList.Destroy;
  100. var
  101. i: Integer;
  102. begin
  103. UsedModules.Free;
  104. for i := 0 to ServerClasses.Count - 1 do
  105. TServerClass(ServerClasses[i]).Free;
  106. ServerClasses.Free;
  107. end;
  108. procedure TRPCList.AddServerClass(const AClassName: String);
  109. var
  110. Element: TPasClassType;
  111. ServerClass: TServerClass;
  112. begin
  113. Element := TPasClassType(Engine.FindElement(AClassName));
  114. if not Assigned(Element) then
  115. begin
  116. WriteLn(StdErr, 'Server class "', AClassName, '" not found!');
  117. Halt(3);
  118. end;
  119. if (not Element.InheritsFrom(TPasClassType)) or
  120. (Element.ObjKind <> okClass) then
  121. begin
  122. WriteLn('"', AClassName, '" is not a class!');
  123. Halt(4);
  124. end;
  125. ServerClass := TServerClass.Create;
  126. ServerClasses.Add(ServerClass);
  127. ServerClass.Element := Element;
  128. ServerClass.ImplName := Copy(Element.Name, 2, Length(Element.Name));
  129. UsedModules.Add(Element.GetModule.Name);
  130. end;
  131. var
  132. OutputFilename, UnitName: String;
  133. RPCList: TRPCList;
  134. procedure WriteClassServerSource(ServerClass: TPasClassType;
  135. ImplementationSection: TPasSection; Method, ProcImpl: TPasProcedureImpl;
  136. const MethodPrefix: String; NestingLevel: Integer);
  137. { Method: Main server method
  138. ProcImpl: Current procedure (may be identical with Method) }
  139. type
  140. TConversionInfo = record
  141. ConverterName: String;
  142. ArgIsParent: Boolean;
  143. end;
  144. function MakeStructConverter(AClass: TPasClassType;
  145. Referrer: TPasProcedureImpl): TPasProcedureImpl; forward;
  146. function MakeArrayConverter(Member, ArraySizeProp: TPasProperty;
  147. ProcessProc, Referrer: TPasProcedureImpl): TPasProcedureImpl; forward;
  148. function FindArraySizeProperty(AArrayProp: TPasProperty): TPasProperty;
  149. var
  150. i: Integer;
  151. Name: String;
  152. begin
  153. Name := Copy(AArrayProp.Name, 1, Length(AArrayProp.Name) - 1) + 'Count';
  154. for i := 0 to TPasClassType(AArrayProp.Parent).Members.Count - 1 do
  155. begin
  156. Result := TPasProperty(TPasClassType(AArrayProp.Parent).Members[i]);
  157. if (Result.ClassType = TPasProperty) and (Result.Visibility = visPublic)
  158. and (CompareStr(Result.Name, Name) = 0) then
  159. exit;
  160. end;
  161. Result := nil;
  162. end;
  163. function GetConversionInfo(Element: TPasElement;
  164. Referrer: TPasProcedureImpl): TConversionInfo;
  165. var
  166. s: String;
  167. ArraySizeProp: TPasProperty;
  168. begin
  169. SetLength(Result.ConverterName, 0);
  170. Result.ArgIsParent := False;
  171. if Element.ClassType = TPasProperty then
  172. begin
  173. ArraySizeProp := FindArraySizeProperty(TPasProperty(Element));
  174. if Assigned(ArraySizeProp) then
  175. begin
  176. Result.ConverterName := MakeArrayConverter(TPasProperty(Element),
  177. ArraySizeProp, ProcImpl, Referrer).Name;
  178. Result.ArgIsParent := True;
  179. exit;
  180. end else
  181. Element := TPasProperty(Element).VarType;
  182. end;
  183. if Element.ClassType = TPasUnresolvedTypeRef then
  184. begin
  185. s := UpperCase(Element.Name);
  186. if (s = 'BYTE') or (s = 'SHORTINT') or (S = 'SMALLINT') or
  187. (s = 'INTEGER') or (s = 'LONGINT') or (s = 'CARDINAL') or
  188. (s = 'INT64') or (s = 'QUADWORD') then
  189. Result.ConverterName := 'AWriter.CreateIntValue'
  190. else if (s = 'BOOLEAN') or (s = 'WORDBOOL') or (s = 'LONGBOOL') then
  191. Result.ConverterName := 'AWriter.CreateBooleanValue'
  192. else if s = 'STRING' then
  193. Result.ConverterName := 'AWriter.CreateStringValue'
  194. else if (s = 'FLOAT') or (s = 'SINGLE') or (s = 'DOUBLE') or
  195. (s = 'EXTENDED') then
  196. Result.ConverterName := 'AWriter.CreateDoubleValue';
  197. end else if Element.ClassType = TPasClassType then
  198. Result.ConverterName := MakeStructConverter(TPasClassType(Element), Referrer).Name;
  199. if Length(Result.ConverterName) = 0 then
  200. raise Exception.Create('Result type not supported: ' + Element.ClassName +
  201. ' ' + Element.Name);
  202. end;
  203. function GetParseValueFnName(PasType: TPasType): String;
  204. var
  205. s: String;
  206. begin
  207. SetLength(Result, 0);
  208. if PasType.ClassType = TPasArgument then
  209. begin
  210. if TPasArgument(PasType).Access = argVar then
  211. raise Exception.Create('"var" arguments are not allowed');
  212. PasType := TPasArgument(PasType).ArgType;
  213. end;
  214. if PasType.ClassType = TPasUnresolvedTypeRef then
  215. begin
  216. s := UpperCase(PasType.Name);
  217. if (s = 'BYTE') or (s = 'SHORTINT') or (S = 'SMALLINT') or
  218. (s = 'INTEGER') or (s = 'LONGINT') or (s = 'CARDINAL') or
  219. (s = 'INT64') or (s = 'QUADWORD') then
  220. Result := 'Int'
  221. else if (s = 'BOOLEAN') or (s = 'WORDBOOL') or (s = 'LONGBOOL') then
  222. Result := 'Boolean'
  223. else if s = 'STRING' then
  224. Result := 'String'
  225. else if (s = 'FLOAT') or (s = 'SINGLE') or (s = 'DOUBLE') or
  226. (s = 'EXTENDED') then
  227. Result := 'Double';
  228. end;
  229. if Length(Result) = 0 then
  230. raise Exception.Create('Argument type not supported: ' +
  231. PasType.ClassName + ' ' + PasType.Name);
  232. end;
  233. function NeedLocalProc(const ProcName: String;
  234. Referrer: TPasProcedureImpl): TPasProcedureImpl;
  235. var
  236. i, j: Integer;
  237. begin
  238. for i := 0 to Method.Locals.Count - 1 do
  239. begin
  240. Result := TPasProcedureImpl(Method.Locals[i]);
  241. if Result.Name = ProcName then
  242. begin
  243. j := Method.Locals.IndexOf(Referrer);
  244. if (j >= 0) and (i >= j) then
  245. begin
  246. // Move existing converter to the top and exit
  247. Method.Locals.Delete(i);
  248. Method.Locals.Insert(Method.Locals.IndexOf(ProcImpl), Result);
  249. end;
  250. exit;
  251. end;
  252. end;
  253. Result := nil;
  254. end;
  255. function MakeStructConverter(AClass: TPasClassType;
  256. Referrer: TPasProcedureImpl): TPasProcedureImpl;
  257. var
  258. ConverterName, s: String;
  259. Commands: TPasImplCommands;
  260. i: Integer;
  261. LocalMember: TPasElement;
  262. ConversionInfo: TConversionInfo;
  263. begin
  264. ConverterName := 'Convert' + AClass.Name;
  265. Result := NeedLocalProc(ConverterName, Referrer);
  266. if Assigned(Result) then
  267. exit;
  268. Result := TPasProcedureImpl.Create(ConverterName, Method);
  269. Method.Locals.Insert(Method.Locals.IndexOf(Referrer), Result);
  270. Result.ProcType := TPasFunctionType.Create('', Result);
  271. Result.ProcType.CreateArgument('Inst', AClass.Name);
  272. TPasFunctionType(Result.ProcType).ResultEl :=
  273. TPasResultElement.Create('', Result);
  274. TPasFunctionType(Result.ProcType).ResultEl.ResultType :=
  275. TPasUnresolvedTypeRef.Create('TXMLRPCStruct', Result);
  276. Result.Body := TPasImplBlock.Create('', Result);
  277. Commands := Result.Body.AddCommands;
  278. Commands.Commands.Add('Result := AWriter.CreateStruct');
  279. for i := 0 to AClass.Members.Count - 1 do
  280. begin
  281. LocalMember := TPasElement(AClass.Members[i]);
  282. if LocalMember.ClassType = TPasProperty then
  283. begin
  284. ConversionInfo := GetConversionInfo(LocalMember, Result);
  285. s := 'AWriter.AddStructMember(Result, ''' + LocalMember.Name + ''', ' +
  286. ConversionInfo.ConverterName;
  287. if ConversionInfo.ArgIsParent then
  288. s := s + '(Inst))'
  289. else
  290. s := s + '(Inst.' + LocalMember.Name + '))';
  291. Commands.Commands.Add(s);
  292. end;
  293. end;
  294. end;
  295. function MakeArrayConverter(Member, ArraySizeProp: TPasProperty;
  296. ProcessProc, Referrer: TPasProcedureImpl): TPasProcedureImpl;
  297. var
  298. i: Integer;
  299. ConverterName, s: String;
  300. Commands: TPasImplCommands;
  301. VarMember: TPasVariable;
  302. ForLoop: TPasImplForLoop;
  303. ConversionInfo: TConversionInfo;
  304. begin
  305. ConverterName := 'Convert' + Member.Parent.Name + '_' + Member.Name;
  306. Result := NeedLocalProc(ConverterName, Referrer);
  307. if Assigned(Result) then
  308. exit;
  309. Result := TPasProcedureImpl.Create(ConverterName, Method);
  310. i := Method.Locals.IndexOf(Referrer);
  311. if i < 0 then
  312. i := 0;
  313. Method.Locals.Insert(i, Result);
  314. Result.ProcType := TPasFunctionType.Create('', Result);
  315. Result.ProcType.CreateArgument('Inst', Member.Parent.Name);
  316. TPasFunctionType(Result.ProcType).ResultEl :=
  317. TPasResultElement.Create('', Result);
  318. TPasFunctionType(Result.ProcType).ResultEl.ResultType :=
  319. TPasUnresolvedTypeRef.Create('TXMLRPCArray', Result);
  320. Result.Body := TPasImplBlock.Create('', Result);
  321. Commands := Result.Body.AddCommands;
  322. Commands.Commands.Add('Result := AWriter.CreateArray');
  323. VarMember := TPasVariable.Create('i', Result);
  324. Result.Locals.Add(VarMember);
  325. VarMember.VarType := TPasUnresolvedTypeRef.Create('Integer', VarMember);
  326. ForLoop := Result.Body.AddForLoop(TPasVariable.Create('i', Result),
  327. '0', MethodPrefix + ArraySizeProp.Name + ' - 1');
  328. ForLoop.Body := TPasImplCommand.Create('', ForLoop);
  329. ConversionInfo := GetConversionInfo(Member.VarType, Result);
  330. s := 'AWriter.AddArrayElement(Result, ' + ConversionInfo.ConverterName;
  331. if ConversionInfo.ArgIsParent then
  332. s := s + '(Inst))'
  333. else
  334. s := s + '(Inst.' + Member.Name + '[i]))';
  335. TPasImplCommand(ForLoop.Body).Command := s;
  336. end;
  337. function CreateDispatcher(VarType: TPasClassType;
  338. Referrer: TPasProcedureImpl): TPasProcedureImpl;
  339. var
  340. DispatcherName: String;
  341. begin
  342. DispatcherName := 'Dispatch' + VarType.Name;
  343. Result := NeedLocalProc(DispatcherName, Referrer);
  344. if Assigned(Result) then
  345. exit;
  346. // Create new dispatcher method
  347. Result := TPasProcedureImpl.Create(DispatcherName, Method);
  348. if ProcImpl = Method then
  349. Method.Locals.Insert(0, Result)
  350. else
  351. Method.Locals.Insert(Method.Locals.IndexOf(Referrer), Result);
  352. Result.ProcType := TPasProcedureType.Create('', Result);
  353. Result.ProcType.CreateArgument('Inst', VarType.Name);
  354. Result.ProcType.CreateArgument('Level', 'Integer');
  355. WriteClassServerSource(VarType,
  356. ImplementationSection, Method, Result, 'Inst.', NestingLevel + 1);
  357. end;
  358. var
  359. IfElse, ParentIfElse: TPasImplIfElse;
  360. procedure CreateBranch(const MethodName: String);
  361. begin
  362. if Assigned(ParentIfElse) then
  363. begin
  364. IfElse := TPasImplIfElse.Create('', ParentIfElse);
  365. ParentIfElse.ElseBranch := IfElse;
  366. end else
  367. begin
  368. IfElse := TPasImplIfElse.Create('', ProcImpl.Body);
  369. ProcImpl.Body.Elements.Add(IfElse);
  370. end;
  371. ParentIfElse := IfElse;
  372. IfElse.Condition := 's = ''' + UpperCase(MethodName) + '''';
  373. end;
  374. procedure ProcessMethodCall(Member: TPasProcedure);
  375. function MakeProcArgs(Args: TList): String;
  376. var
  377. i: Integer;
  378. begin
  379. if (not Assigned(Args)) or (Args.Count = 0) then
  380. Result := ''
  381. else
  382. begin
  383. Result := '(';
  384. for i := 0 to Args.Count - 1 do
  385. begin
  386. if i > 0 then
  387. Result := Result + ', ';
  388. Result := Result + 'AParser.GetPrev' + GetParseValueFnName(TPasType(Args[i]));
  389. end;
  390. Result := Result + ')';
  391. end;
  392. end;
  393. var
  394. Commands: TPasImplCommands;
  395. begin
  396. CreateBranch(Member.Name);
  397. Commands := TPasImplCommands.Create('', IfElse);
  398. IfElse.IfBranch := Commands;
  399. if TPasProcedure(Member).ProcType.Args.Count > 0 then
  400. Commands.Commands.Add('AParser.ResetValueCursor');
  401. if Member.ClassType = TPasProcedure then
  402. begin
  403. Commands.Commands.Add(MethodPrefix + Member.Name +
  404. MakeProcArgs(TPasProcedure(Member).ProcType.Args));
  405. Commands.Commands.Add('AWriter.WriteResponse(nil)');
  406. end else
  407. begin
  408. // function
  409. Commands.Commands.Add('AWriter.WriteResponse(' +
  410. GetConversionInfo(TPasFunctionType(TPasFunction(Member).ProcType).
  411. ResultEl.ResultType, ProcImpl).ConverterName + '(' + MethodPrefix +
  412. Member.Name + MakeProcArgs(TPasProcedure(Member).ProcType.Args) + '))');
  413. end;
  414. end;
  415. procedure ProcessProperty(Member: TPasProperty);
  416. var
  417. LocalIfElse: TPasImplIfElse;
  418. IsArray, IsStruct: Boolean;
  419. s, s2: String;
  420. Commands: TPasImplCommands;
  421. Command: TPasImplCommand;
  422. ConversionInfo: TConversionInfo;
  423. begin
  424. if Member.ReadAccessorName <> '' then
  425. begin
  426. CreateBranch('Get' + Member.Name);
  427. IsArray := (Member.Args.Count = 1) and
  428. Assigned(FindArraySizeProperty(Member));
  429. IsStruct := Member.VarType.ClassType = TPasClassType;
  430. if IsStruct then
  431. s := CreateDispatcher(TPasClassType(Member.VarType), ProcImpl).Name +
  432. '(' + MethodPrefix + Member.Name;
  433. if NestingLevel = 0 then
  434. s2 := '1'
  435. else
  436. s2 := 'Level + 1';
  437. if IsArray or (IsStruct and (Member.Args.Count = 0)) then
  438. begin
  439. LocalIfElse := TPasImplIfElse.Create('', IfElse);
  440. IfElse.IfBranch := LocalIfElse;
  441. LocalIfElse.Condition := 'APath.Count <= ' + s2;
  442. end;
  443. if IsStruct then
  444. if IsArray then
  445. begin
  446. LocalIfElse.IfBranch := TPasImplCommand.Create('', LocalIfElse);
  447. TPasImplCommand(LocalIfElse.IfBranch).Command :=
  448. 'AWriter.WriteResponse(' +
  449. GetConversionInfo(Member, ProcImpl).ConverterName + '(' +
  450. Copy(MethodPrefix, 1, Length(MethodPrefix) - 1) + '))';
  451. LocalIfElse.ElseBranch := TPasImplCommand.Create('', LocalIfElse);
  452. TPasImplCommand(LocalIfElse.ElseBranch).Command :=
  453. s + '[AParser.GetNext' +
  454. GetParseValueFnName(TPasArgument(Member.Args[0]).ArgType) + '], ' +
  455. s2 + ')';
  456. end else
  457. begin
  458. if Member.Args.Count = 0 then
  459. begin
  460. LocalIfElse.IfBranch := TPasImplCommand.Create('', LocalIfElse);
  461. TPasImplCommand(LocalIfElse.IfBranch).Command :=
  462. 'AWriter.WriteResponse(' +
  463. GetConversionInfo(Member, ProcImpl).ConverterName + '(' +
  464. MethodPrefix + Member.Name + '))';
  465. LocalIfElse.ElseBranch := TPasImplCommand.Create('', LocalIfElse);
  466. TPasImplCommand(LocalIfElse.ElseBranch).Command := s + ', ' + s2 + ')';
  467. end else
  468. begin
  469. IfElse.IfBranch := TPasImplCommand.Create('', IfElse);
  470. TPasImplCommand(IfElse.IfBranch).Command := s + '[AParser.GetNext' +
  471. GetParseValueFnName(TPasArgument(Member.Args[0]).ArgType) + '], ' +
  472. s2 + ')';
  473. end;
  474. end
  475. else if IsArray then
  476. begin
  477. LocalIfElse.IfBranch := TPasImplCommand.Create('', LocalIfElse);
  478. TPasImplCommand(LocalIfElse.IfBranch).Command :=
  479. 'AWriter.WriteResponse(' +
  480. GetConversionInfo(Member, ProcImpl).ConverterName + '(' +
  481. Copy(MethodPrefix, 1, Length(MethodPrefix) - 1) + '))';
  482. LocalIfElse.ElseBranch := TPasImplCommand.Create('', LocalIfElse);
  483. TPasImplCommand(LocalIfElse.ElseBranch).Command :=
  484. 'AWriter.WriteResponse(' +
  485. GetConversionInfo(Member.VarType, ProcImpl).ConverterName + '(' +
  486. MethodPrefix + Member.Name + '[AParser.GetNext' +
  487. GetParseValueFnName(TPasArgument(Member.Args[0]).ArgType) + ']))';
  488. end else
  489. begin
  490. IfElse.IfBranch := TPasImplCommand.Create('', IfElse);
  491. TPasImplCommand(IfElse.IfBranch).Command := 'AWriter.WriteResponse(' +
  492. GetConversionInfo(Member.VarType, ProcImpl).ConverterName + '(' +
  493. MethodPrefix + Member.Name + '))';
  494. end;
  495. end;
  496. if Member.WriteAccessorName <> '' then
  497. begin
  498. CreateBranch('Set' + Member.Name);
  499. Commands := TPasImplCommands.Create('', IfElse);
  500. IfElse.IfBranch := Commands;
  501. Commands.Commands.Add('// Not supported by mkxmlrpc yet');
  502. end;
  503. end;
  504. var
  505. VarMember: TPasVariable;
  506. i: Integer;
  507. Command: TPasImplCommand;
  508. Member: TPasElement;
  509. begin
  510. VarMember := TPasVariable.Create('s', ProcImpl);
  511. ProcImpl.Locals.Add(VarMember);
  512. VarMember.VarType := TPasUnresolvedTypeRef.Create('String', VarMember);
  513. ProcImpl.Body := TPasImplBlock.Create('', ProcImpl);
  514. if NestingLevel = 0 then
  515. ProcImpl.Body.AddCommand('s := APath[' + IntToStr(NestingLevel) + ']')
  516. else
  517. ProcImpl.Body.AddCommand('s := APath[Level]');
  518. ParentIfElse := nil;
  519. for i := 0 to ServerClass.Members.Count - 1 do
  520. begin
  521. Member := TPasElement(ServerClass.Members[i]);
  522. if Member.Visibility <> visPublic then
  523. continue;
  524. if (Member.ClassType = TPasProcedure) or (Member.ClassType = TPasFunction)
  525. then
  526. ProcessMethodCall(TPasProcedure(Member))
  527. else if Member.ClassType = TPasProperty then
  528. ProcessProperty(TPasProperty(Member))
  529. else if (Member.ClassType <> TPasConstructor) and
  530. (Member.ClassType <> TPasDestructor) then
  531. WriteLn('Warning: Unsupportet member type: ', Member.ElementTypeName);
  532. end;
  533. if Assigned(ParentIfElse) then
  534. begin
  535. Command := TPasImplCommand.Create('', ParentIfElse);
  536. ParentIfElse.ElseBranch := Command;
  537. end else
  538. begin
  539. Command := TPasImplCommand.Create('', ProcImpl.Body);
  540. ProcImpl.Body.Elements.Add(Command);
  541. end;
  542. Command.Command := 'AWriter.WriteFaultResponse(2, ''Invalid method name'')';
  543. end;
  544. procedure WriteFPCServerSource;
  545. var
  546. i: Integer;
  547. Module: TPasModule;
  548. InterfaceSection, ImplementationSection: TPasSection;
  549. VarMember: TPasVariable;
  550. PropertyMember: TPasProperty;
  551. ProcMember: TPasProcedure;
  552. Arg: TPasArgument;
  553. ServerClass: TPasClassType;
  554. Stream: TStream;
  555. ProcImpl: TPasProcedureImpl;
  556. begin
  557. Module := TPasModule.Create(UnitName, nil);
  558. try
  559. InterfaceSection := TPasSection.Create('', Module);
  560. Module.InterfaceSection := InterfaceSection;
  561. ImplementationSection := TPasSection.Create('', Module);
  562. Module.ImplementationSection := ImplementationSection;
  563. InterfaceSection.AddUnitToUsesList('Classes');
  564. InterfaceSection.AddUnitToUsesList('XMLRPC');
  565. for i := 0 to RPCList.UsedModules.Count - 1 do
  566. InterfaceSection.AddUnitToUsesList(RPCList.UsedModules[i]);
  567. for i := 0 to RPCList.ServerClasses.Count - 1 do
  568. with TServerClass(RPCList.ServerClasses[i]) do
  569. begin
  570. ServerClass := TPasClassType.Create('T' + ImplName + 'XMLRPCServlet',
  571. InterfaceSection);
  572. InterfaceSection.Declarations.Add(ServerClass);
  573. ServerClass.ObjKind := okClass;
  574. ServerClass.AncestorType :=
  575. TPasUnresolvedTypeRef.Create('TXMLRPCServlet', ServerClass);
  576. // Create private field which holds the implementation instance
  577. VarMember := TPasVariable.Create('F' + ImplName, ServerClass);
  578. VarMember.Visibility := visPrivate;
  579. VarMember.VarType := TPasUnresolvedTypeRef.Create(Element.Name, VarMember);
  580. ServerClass.Members.Add(VarMember);
  581. // Create dispatcher method
  582. ProcMember := TPasProcedure.Create('Dispatch', ServerClass);
  583. ProcMember.Visibility := visProtected;
  584. ProcMember.IsOverride := True;
  585. ProcMember.ProcType := TPasProcedureType.Create('', ProcMember);
  586. ProcMember.ProcType.CreateArgument('AParser', 'TXMLRPCParser').
  587. Visibility := visPublic;
  588. ProcMember.ProcType.CreateArgument('AWriter', 'TXMLRPCWriter').
  589. Visibility := visPublic;
  590. ProcMember.ProcType.CreateArgument('APath', 'TStrings').
  591. Visibility := visPublic;
  592. ServerClass.Members.Add(ProcMember);
  593. // Create published property for implementation instance
  594. PropertyMember := TPasProperty.Create(ImplName, ServerClass);
  595. PropertyMember.Visibility := visPublished;
  596. PropertyMember.VarType := VarMember.VarType;
  597. VarMember.VarType.AddRef;
  598. PropertyMember.ReadAccessorName := 'F' + ImplName;
  599. PropertyMember.WriteAccessorName := 'F' + ImplName;
  600. ServerClass.Members.Add(PropertyMember);
  601. // Create dispatcher implementation
  602. ProcImpl := TPasProcedureImpl.Create('Dispatch', ServerClass);
  603. ImplementationSection.Declarations.Add(ProcImpl);
  604. ProcImpl.ProcType := ProcMember.ProcType;
  605. ProcMember.ProcType.AddRef;
  606. ProcImpl.ProcType.AddRef;
  607. WriteClassServerSource(Element, ImplementationSection, ProcImpl,
  608. ProcImpl, ImplName + '.', 0);
  609. end;
  610. Stream := THandleStream.Create(StdOutputHandle);
  611. try
  612. WritePasFile(Module, Stream);
  613. finally
  614. Stream.Free;
  615. end;
  616. Stream := TFileStream.Create(OutputFilename, fmCreate);
  617. try
  618. WritePasFile(Module, Stream);
  619. finally
  620. Stream.Free;
  621. end;
  622. finally
  623. Module.Free;
  624. end;
  625. end;
  626. var
  627. i, j: Integer;
  628. s, Cmd, Arg: String;
  629. InputFiles, ClassList: TStringList;
  630. begin
  631. InputFiles := TStringList.Create;
  632. ClassList := TStringList.Create;
  633. try
  634. for i := 1 to ParamCount do
  635. begin
  636. s := ParamStr(i);
  637. j := Pos('=', s);
  638. if j > 0 then
  639. begin
  640. Cmd := Copy(s, 1, j - 1);
  641. Arg := Copy(s, j + 1, Length(s));
  642. end else
  643. begin
  644. Cmd := s;
  645. SetLength(Arg, 0);
  646. end;
  647. if (Cmd = '-i') or (Cmd = '--input') then
  648. InputFiles.Add(Arg)
  649. else if Cmd = '--output' then
  650. OutputFilename := Arg
  651. else if Cmd = '--unitname' then
  652. UnitName := Arg
  653. else if Cmd = '--serverclass' then
  654. ClassList.Add(Arg)
  655. else
  656. WriteLn(StdErr, Format(SCmdLineInvalidOption, [s]));
  657. end;
  658. if ClassList.Count = 0 then
  659. begin
  660. WriteLn(StdErr, SNoServerClassNameProvided);
  661. Halt(2);
  662. end;
  663. if UnitName = '' then
  664. begin
  665. WriteLn(StdErr, SNoUnitNameProvided);
  666. Halt(2);
  667. end;
  668. Engine := TParserEngine.Create;
  669. try
  670. // Engine.SetPackageName('XMLRPC');
  671. for i := 0 to InputFiles.Count - 1 do
  672. ParseSource(Engine, InputFiles[i], '', '');
  673. RPCList := TRPCList.Create;
  674. try
  675. for i := 0 to ClassList.Count - 1 do
  676. RPCList.AddServerClass(ClassList[i]);
  677. WriteFPCServerSource;
  678. finally
  679. RPCList.Free;
  680. end;
  681. finally
  682. Engine.Free;
  683. end;
  684. finally
  685. InputFiles.Free;
  686. ClassList.Free;
  687. end;
  688. end.
  689. {
  690. $Log$
  691. Revision 1.1 2003-04-26 16:42:10 sg
  692. * Added mkxmlrpc
  693. }