webidl2pas.pp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. {
  2. This file is part of the Free Component Library
  3. WEBIDL to pascal code converter program
  4. Copyright (c) 2022 by Michael Van Canneyt [email protected]
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. program webidl2pas;
  12. {$mode objfpc}{$H+}
  13. uses
  14. Classes, SysUtils, CustApp, webidlscanner, webidltopas, pascodegen, typinfo,
  15. webidltopas2js, webidltowasmjob;
  16. type
  17. TWebIDLToPasFormat = (
  18. wifPas2js,
  19. wifWasmJob
  20. );
  21. const
  22. WebIDLToPasFormatNames: array[TWebIDLToPasFormat] of string = (
  23. 'pas2js',
  24. 'wasmjob'
  25. );
  26. type
  27. { TWebIDLToPasApplication }
  28. TWebIDLToPasApplication = class(TCustomApplication)
  29. private
  30. FOutputFormat: TWebIDLToPasFormat;
  31. FWebIDLToPas: TBaseWebIDLToPas;
  32. function CheckBaseOption(C: TBaseConversionOption;
  33. const AShort: Char; const aLong: String): Boolean;
  34. function CheckPas2jsOption(C: TPas2jsConversionOption;
  35. const AShort: Char; const aLong: String): Boolean;
  36. procedure DoConvertLog(Sender: TObject; {%H-}LogType: TCodegenLogType; const Msg: String);
  37. function GetInputFileName: String;
  38. function GetOutputFileName: String;
  39. function GetUnitName: String;
  40. procedure SetinputFileName(AValue: String);
  41. procedure SetOutputFileName(AValue: String);
  42. procedure SetunitName(AValue: String);
  43. protected
  44. procedure DoRun; override;
  45. procedure InitWebIDLToPas; virtual;
  46. Protected
  47. Property WebIDLToPas : TBaseWebIDLToPas Read FWebIDLToPas;
  48. public
  49. constructor Create(TheOwner: TComponent); override;
  50. destructor Destroy; override;
  51. procedure WriteHelp(Const Msg : string); virtual;
  52. Property UnitName : String Read GetUnitName Write SetunitName;
  53. property InputFileName : String Read GetInputFileName Write SetinputFileName;
  54. property OutputFileName : String Read GetOutputFileName Write SetOutputFileName;
  55. property OutputFormat: TWebIDLToPasFormat read FOutputFormat write FOutputFormat;
  56. end;
  57. { TWebIDLToPasApplication }
  58. function TWebIDLToPasApplication.GetInputFileName: String;
  59. begin
  60. Result:=FWebIDLToPas.InputFileName;
  61. end;
  62. procedure TWebIDLToPasApplication.DoConvertLog(Sender: TObject;
  63. LogType: TCodegenLogType; const Msg: String);
  64. begin
  65. {AllowWriteln}
  66. Writeln(Msg);
  67. {AllowWriteln-}
  68. end;
  69. function TWebIDLToPasApplication.GetOutputFileName: String;
  70. begin
  71. Result:=FWebIDLToPas.OutputFileName
  72. end;
  73. function TWebIDLToPasApplication.GetUnitName: String;
  74. begin
  75. Result:=FWebIDLToPas.OutputUnitName;
  76. end;
  77. procedure TWebIDLToPasApplication.SetinputFileName(AValue: String);
  78. begin
  79. FWebIDLToPas.InputFileName:=aValue;
  80. end;
  81. procedure TWebIDLToPasApplication.SetOutputFileName(AValue: String);
  82. begin
  83. FWebIDLToPas.OutputFileName:=aValue;
  84. end;
  85. procedure TWebIDLToPasApplication.SetunitName(AValue: String);
  86. begin
  87. FWebIDLToPas.OutputUnitName:=aValue;
  88. end;
  89. function TWebIDLToPasApplication.CheckBaseOption(C: TBaseConversionOption;
  90. const AShort: Char; const aLong: String): Boolean;
  91. begin
  92. Result:=HasOption(aShort,ALong);
  93. if Result then
  94. FWebIDLToPas.BaseOptions:=FWebIDLToPas.BaseOptions+[C];
  95. end;
  96. function TWebIDLToPasApplication.CheckPas2jsOption(C: TPas2jsConversionOption;
  97. const AShort: Char; const aLong: String): Boolean;
  98. begin
  99. if not (FWebIDLToPas is TWebIDLToPas2js) then exit;
  100. Result:=HasOption(aShort,ALong);
  101. if Result then
  102. TWebIDLToPas2js(FWebIDLToPas).Pas2jsOptions:=TWebIDLToPas2js(FWebIDLToPas).Pas2jsOptions+[C];
  103. end;
  104. procedure TWebIDLToPasApplication.DoRun;
  105. procedure E(const Msg: string);
  106. begin
  107. {AllowWriteln}
  108. writeln('Error: ',Msg);
  109. {AllowWriteln-}
  110. Halt(1);
  111. end;
  112. var
  113. A,ErrorMsg: String;
  114. I : Integer;
  115. ok: Boolean;
  116. f: TWebIDLToPasFormat;
  117. begin
  118. Terminate;
  119. // quick check parameters
  120. ErrorMsg:=CheckOptions('ced::f:g:hi:m:n:o:pt:u:vw:x:', [
  121. 'help',
  122. 'constexternal',
  123. 'dicttoclass::',
  124. 'expandunionargs',
  125. 'outputformat:',
  126. 'globals:',
  127. 'input:',
  128. 'implementation:',
  129. 'include:',
  130. 'output:',
  131. 'optionsinheader',
  132. 'typealiases:',
  133. 'unitname:',
  134. 'verbose',
  135. 'webidlversion:',
  136. 'extra:'
  137. ]);
  138. if (ErrorMsg<>'') or HasOption('h','help') then
  139. begin
  140. ErrorMsg:='Missing input filename';
  141. WriteHelp(ErrorMsg);
  142. Exit();
  143. end;
  144. // first read outputformat and create FWebIDLToPas
  145. if HasOption('f','outputformat') then
  146. begin
  147. A:=GetOptionValue('f','outputformat');
  148. ok:=false;
  149. for f in TWebIDLToPasFormat do
  150. begin
  151. if SameText(A,WebIDLToPasFormatNames[f]) then
  152. begin
  153. OutputFormat:=f;
  154. ok:=true;
  155. end;
  156. end;
  157. if not ok then
  158. E('unknown outputformat "'+A+'"');
  159. end;
  160. InitWebIDLToPas;
  161. // then set verbosity
  162. FWebIDLToPas.Verbose:=HasOption('v','verbose');
  163. // read other options
  164. CheckPas2jsOption(p2jcoExternalConst,'c','constexternal');
  165. if CheckBaseOption(coDictionaryAsClass,'d','dicttoclass') then
  166. TWebIDLToPas2js(FWebIDLToPas).DictionaryClassParent:=GetOptionValue('d','dicttoclass');
  167. CheckBaseOption(coExpandUnionTypeArgs,'e','expandunionargs');
  168. // -f ?
  169. A:=GetOptionValue('g','globals');
  170. if (Copy(A,1,1)='@') then
  171. begin
  172. Delete(A,1,1);
  173. FWebIDLToPas.GlobalVars.LoadFromFile(A);
  174. end
  175. else
  176. FWebIDLToPas.GlobalVars.CommaText:=A;
  177. InputFileName:=GetOptionValue('i','input');
  178. if (InputFileName='') then
  179. begin
  180. WriteHelp('Missing input filename');
  181. Exit();
  182. end;
  183. if HasOption('m','implementation') then
  184. FWebIDLToPas.IncludeImplementationCode.LoadFromFile(GetOptionValue('m','implementation'));
  185. if HasOption('n','include') then
  186. FWebIDLToPas.IncludeInterfaceCode.LoadFromFile(GetOptionValue('n','include'));
  187. OutputFileName:=GetOptionValue('o','output');
  188. CheckBaseOption(coAddOptionsToHeader,'p','optionsinheader');
  189. A:=GetOptionValue('t','typealiases');
  190. if (Copy(A,1,1)='@') then
  191. begin
  192. Delete(A,1,1);
  193. FWebIDLToPas.TypeAliases.LoadFromFile(A);
  194. end
  195. else
  196. FWebIDLToPas.TypeAliases.CommaText:=A;
  197. UnitName:=GetOptionValue('u','unitname');
  198. if UnitName='' then
  199. UnitName:=ChangeFileExt(ExtractFileName(InputFileName),'');
  200. if OutputFileName='' then
  201. begin
  202. if (UnitName<>'') then
  203. OutputFileName:=ExtractFilePath(InputFileName)+UnitName+'.pas';
  204. end;
  205. if HasOption('w','webidlversion') then
  206. begin
  207. A:=GetOptionValue('w','webidlversion');
  208. I:=GetEnumValue(TypeInfo(TWebIDLVersion),A);
  209. if (I<>-1) then
  210. FWebIDLToPas.WebIDLVersion:=TWebIDLVersion(I)
  211. else
  212. E('Invalid webidl version: "'+A+'"');
  213. end;
  214. FWebIDLToPas.ExtraUnits:=GetOptionValue('x','extra');
  215. FWebIDLToPas.Execute;
  216. // stop program loop
  217. Terminate;
  218. end;
  219. procedure TWebIDLToPasApplication.InitWebIDLToPas;
  220. begin
  221. case OutputFormat of
  222. wifWasmJob:
  223. FWebIDLToPas:=TWebIDLToPasWasmJob.Create(Self);
  224. else
  225. FWebIDLToPas:=TWebIDLToPas2js.Create(Self);
  226. end;
  227. FWebIDLToPas.OnLog:=@DoConvertLog;
  228. FWebIDLToPas.ClassPrefix:='TJS';
  229. FWebIDLToPas.ClassSuffix:='';
  230. FWebIDLToPas.KeywordSuffix:='_';
  231. FWebIDLToPas.KeywordPrefix:='';
  232. end;
  233. constructor TWebIDLToPasApplication.Create(TheOwner: TComponent);
  234. begin
  235. inherited Create(TheOwner);
  236. StopOnException:=True;
  237. ExceptionExitCode:=1;
  238. end;
  239. destructor TWebIDLToPasApplication.Destroy;
  240. begin
  241. FreeAndNil(FWebIDLToPas);
  242. inherited Destroy;
  243. end;
  244. procedure TWebIDLToPasApplication.WriteHelp(const Msg: string);
  245. begin
  246. {AllowWriteln}
  247. if (Msg<>'') then
  248. Writeln(StdErr,'Error : ',Msg);
  249. writeln(StdErr,'Usage: ', ExeName, ' [options]');
  250. Writeln(StdErr,'Where option is one or more of');
  251. Writeln(StdErr,'-h --help this help text');
  252. Writeln(StdErr,'-c --constexternal Write consts as external const (no value)');
  253. Writeln(StdErr,'-d --dicttoclass[=Parent] Write dictionaries as classes');
  254. Writeln(StdErr,'-e --expandunionargs Add overloads for all Union typed function arguments');
  255. Writeln(StdErr,'-f --outputformat=[pas2js|wasmjob] Output format, default ',WebIDLToPasFormatNames[OutputFormat]);
  256. Writeln(StdErr,'-g --globals=list A comma separated list of global vars');
  257. Writeln(StdErr,' use @filename to load the globals from file.');
  258. Writeln(StdErr,' wasmjob: PasVarName=JSClassName,JOBRegisterName');
  259. Writeln(StdErr,'-i --input=FileName input webidl file');
  260. Writeln(StdErr,'-m --implementation=Filename include file as implementation');
  261. Writeln(StdErr,'-n --include=Filename include file at end of interface');
  262. Writeln(StdErr,'-o --output=FileName output file. Defaults to unit name with .pas extension appended.');
  263. Writeln(StdErr,'-p --optionsinheader add options to header of generated file');
  264. Writeln(StdErr,'-t --typealiases=alias A comma separated list of type aliases in Alias=Name form');
  265. Writeln(StdErr,' use @filename to load the aliases from file.');
  266. Writeln(StdErr,'-u --unitname=Name name for unit. Defaults to input file without extension.');
  267. Writeln(StdErr,'-v --verbose Output some diagnostic information');
  268. Writeln(StdErr,'-w --webidlversion=V Set web IDL version. Allowed values: v1 or v2');
  269. Writeln(StdErr,'-x --extra=units Extra units to put in uses clause (comma separated list)');
  270. ExitCode:=Ord(Msg<>'');
  271. {AllowWriteln-}
  272. end;
  273. var
  274. Application: TWebIDLToPasApplication;
  275. begin
  276. Application:=TWebIDLToPasApplication.Create(nil);
  277. Application.Title:='WebIDL To Pascal converter Application';
  278. Application.Run;
  279. Application.Free;
  280. end.