webidl2pas.pp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  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, webidltowasmstub;
  16. type
  17. TWebIDLToPasFormat = (
  18. wifPas2js,
  19. wifWasmJob,
  20. wifWasmJobStub
  21. );
  22. const
  23. WebIDLToPasFormatNames: array[TWebIDLToPasFormat] of string = (
  24. 'pas2js',
  25. 'wasmjob',
  26. 'wasmjobstub'
  27. );
  28. type
  29. { TWebIDLToPasApplication }
  30. TWebIDLToPasApplication = class(TCustomApplication)
  31. private
  32. FOutputFormat: TWebIDLToPasFormat;
  33. FWebIDLToPas: TBaseWebIDLToPas;
  34. function CheckBaseOption(C: TBaseConversionOption;
  35. const AShort: Char; const aLong: String): Boolean;
  36. function CheckPas2jsOption(C: TPas2jsConversionOption;
  37. const AShort: Char; const aLong: String): Boolean;
  38. function ConfigWebIDLToPas: Boolean;
  39. procedure DoConvertLog(Sender: TObject; {%H-}LogType: TCodegenLogType; const Msg: String);
  40. function GetInputFileName: String;
  41. function GetOutputFileName: String;
  42. function GetUnitName: String;
  43. procedure SetinputFileName(AValue: String);
  44. procedure SetOutputFileName(AValue: String);
  45. procedure SetunitName(AValue: String);
  46. protected
  47. procedure DoRun; override;
  48. procedure InitWebIDLToPas; virtual;
  49. Protected
  50. Property WebIDLToPas : TBaseWebIDLToPas Read FWebIDLToPas;
  51. public
  52. constructor Create(TheOwner: TComponent); override;
  53. destructor Destroy; override;
  54. procedure WriteHelp(Const Msg : string); virtual;
  55. Property UnitName : String Read GetUnitName Write SetunitName;
  56. property InputFileName : String Read GetInputFileName Write SetinputFileName;
  57. property OutputFileName : String Read GetOutputFileName Write SetOutputFileName;
  58. property OutputFormat: TWebIDLToPasFormat read FOutputFormat write FOutputFormat;
  59. end;
  60. { TWebIDLToPasApplication }
  61. function TWebIDLToPasApplication.GetInputFileName: String;
  62. begin
  63. Result:=FWebIDLToPas.InputFileName;
  64. end;
  65. procedure TWebIDLToPasApplication.DoConvertLog(Sender: TObject;
  66. LogType: TCodegenLogType; const Msg: String);
  67. begin
  68. {AllowWriteln}
  69. Writeln(Msg);
  70. {AllowWriteln-}
  71. end;
  72. function TWebIDLToPasApplication.GetOutputFileName: String;
  73. begin
  74. Result:=FWebIDLToPas.OutputFileName
  75. end;
  76. function TWebIDLToPasApplication.GetUnitName: String;
  77. begin
  78. Result:=FWebIDLToPas.OutputUnitName;
  79. end;
  80. procedure TWebIDLToPasApplication.SetinputFileName(AValue: String);
  81. begin
  82. FWebIDLToPas.InputFileName:=aValue;
  83. end;
  84. procedure TWebIDLToPasApplication.SetOutputFileName(AValue: String);
  85. begin
  86. FWebIDLToPas.OutputFileName:=aValue;
  87. end;
  88. procedure TWebIDLToPasApplication.SetunitName(AValue: String);
  89. begin
  90. FWebIDLToPas.OutputUnitName:=aValue;
  91. end;
  92. function TWebIDLToPasApplication.CheckBaseOption(C: TBaseConversionOption;
  93. const AShort: Char; const aLong: String): Boolean;
  94. begin
  95. Result:=HasOption(aShort,ALong);
  96. if Result then
  97. FWebIDLToPas.BaseOptions:=FWebIDLToPas.BaseOptions+[C];
  98. end;
  99. function TWebIDLToPasApplication.CheckPas2jsOption(C: TPas2jsConversionOption;
  100. const AShort: Char; const aLong: String): Boolean;
  101. begin
  102. if not (FWebIDLToPas is TWebIDLToPas2js) then exit;
  103. Result:=HasOption(aShort,ALong);
  104. if Result then
  105. TWebIDLToPas2js(FWebIDLToPas).Pas2jsOptions:=TWebIDLToPas2js(FWebIDLToPas).Pas2jsOptions+[C];
  106. end;
  107. // Return true if the configuration was OK.
  108. function TWebIDLToPasApplication.ConfigWebIDLToPas : Boolean;
  109. var
  110. A: String;
  111. I : Integer;
  112. L : TStrings;
  113. begin
  114. Result:=True;
  115. // set verbosity
  116. FWebIDLToPas.Verbose:=HasOption('v','verbose');
  117. // read other options
  118. CheckPas2jsOption(p2jcoExternalConst,'c','constexternal');
  119. if CheckBaseOption(coDictionaryAsClass,'d','dicttoclass') then
  120. TWebIDLToPas2js(FWebIDLToPas).DictionaryClassParent:=GetOptionValue('d','dicttoclass');
  121. CheckBaseOption(coExpandUnionTypeArgs,'e','expandunionargs');
  122. CheckBaseOption(coChromeWindow,'r','chrome');
  123. CheckBaseOption(coPrivateMethods,'a','private');
  124. // -f ?
  125. A:=GetOptionValue('g','globals');
  126. if (Copy(A,1,1)='@') then
  127. begin
  128. Delete(A,1,1);
  129. FWebIDLToPas.GlobalVars.LoadFromFile(A);
  130. end
  131. else
  132. FWebIDLToPas.GlobalVars.CommaText:=A;
  133. A:=GetOptionValue('b','banned');
  134. if (Copy(A,1,1)='@') then
  135. begin
  136. Delete(A,1,1);
  137. FWebIDLToPas.Banned.LoadFromFile(A);
  138. end
  139. else
  140. FWebIDLToPas.Banned.CommaText:=A;
  141. if HasOption('l','list') then
  142. begin
  143. L:=TStringList.Create;
  144. try
  145. A:=GetOptionValue('l','list');
  146. if (Copy(A,1,1)='@') then
  147. begin
  148. Delete(A,1,1);
  149. L.LoadFromFile(A);
  150. end
  151. else
  152. L.CommaText:=A;
  153. FWebIDLToPas.SetUsedList(L);
  154. finally
  155. L.free;
  156. end;
  157. end;
  158. InputFileName:=GetOptionValue('i','input');
  159. if (InputFileName='') then
  160. begin
  161. WriteHelp('Missing input filename');
  162. Exit(False);
  163. end;
  164. if HasOption('m','implementation') then
  165. FWebIDLToPas.IncludeImplementationCode.LoadFromFile(GetOptionValue('m','implementation'));
  166. if HasOption('n','include') then
  167. FWebIDLToPas.IncludeInterfaceCode.LoadFromFile(GetOptionValue('n','include'));
  168. OutputFileName:=GetOptionValue('o','output');
  169. CheckBaseOption(coAddOptionsToHeader,'p','optionsinheader');
  170. A:=GetOptionValue('t','typealiases');
  171. if (Copy(A,1,1)='@') then
  172. begin
  173. Delete(A,1,1);
  174. FWebIDLToPas.TypeAliases.LoadFromFile(A);
  175. end
  176. else
  177. FWebIDLToPas.TypeAliases.CommaText:=A;
  178. UnitName:=GetOptionValue('u','unitname');
  179. if UnitName='' then
  180. UnitName:=ChangeFileExt(ExtractFileName(InputFileName),'');
  181. if OutputFileName='' then
  182. begin
  183. if (UnitName<>'') then
  184. OutputFileName:=ExtractFilePath(InputFileName)+UnitName+'.pas';
  185. end;
  186. if HasOption('w','webidlversion') then
  187. begin
  188. A:=GetOptionValue('w','webidlversion');
  189. I:=GetEnumValue(TypeInfo(TWebIDLVersion),A);
  190. if (I<>-1) then
  191. FWebIDLToPas.WebIDLVersion:=TWebIDLVersion(I)
  192. else
  193. begin
  194. WriteHelp('Invalid webidl version: "'+A+'"');
  195. Exit(False);
  196. end;
  197. end;
  198. FWebIDLToPas.ExtraUnits:=GetOptionValue('x','extra');
  199. end;
  200. procedure TWebIDLToPasApplication.DoRun;
  201. const
  202. Short = 'ced::f:g:hi:m:n:o:pt:u:vw:x:rl:ab';
  203. Long : Array of string = (
  204. 'help',
  205. 'constexternal',
  206. 'dicttoclass::',
  207. 'expandunionargs',
  208. 'outputformat:',
  209. 'globals:',
  210. 'input:',
  211. 'implementation:',
  212. 'include:',
  213. 'output:',
  214. 'optionsinheader',
  215. 'typealiases:',
  216. 'unitname:',
  217. 'verbose',
  218. 'webidlversion:',
  219. 'extra:',
  220. 'chrome',
  221. 'list:',
  222. 'private',
  223. 'banned:'
  224. );
  225. var
  226. A,ErrorMsg: String;
  227. ok: Boolean;
  228. f: TWebIDLToPasFormat;
  229. begin
  230. Terminate;
  231. // quick check parameters
  232. ErrorMsg:=CheckOptions(Short,Long);
  233. if (ErrorMsg<>'') or HasOption('h','help') then
  234. begin
  235. ErrorMsg:='Missing input filename';
  236. WriteHelp(ErrorMsg);
  237. Exit();
  238. end;
  239. // first read outputformat and create FWebIDLToPas
  240. if HasOption('f','outputformat') then
  241. begin
  242. A:=GetOptionValue('f','outputformat');
  243. ok:=false;
  244. for f in TWebIDLToPasFormat do
  245. begin
  246. if SameText(A,WebIDLToPasFormatNames[f]) then
  247. begin
  248. OutputFormat:=f;
  249. ok:=true;
  250. end;
  251. end;
  252. if not ok then
  253. begin
  254. WriteHelp('unknown outputformat "'+A+'"');
  255. exit;
  256. end;
  257. end;
  258. InitWebIDLToPas;
  259. if ConfigWebIDLToPas then
  260. FWebIDLToPas.Execute;
  261. end;
  262. procedure TWebIDLToPasApplication.InitWebIDLToPas;
  263. begin
  264. case OutputFormat of
  265. wifWasmJob:
  266. FWebIDLToPas:=TWebIDLToPasWasmJob.Create(Self);
  267. wifWasmJobStub:
  268. FWebIDLToPas:=TWebIDLToPasWasmJobStub.Create(Self);
  269. else
  270. FWebIDLToPas:=TWebIDLToPas2js.Create(Self);
  271. end;
  272. FWebIDLToPas.OnLog:=@DoConvertLog;
  273. FWebIDLToPas.ClassPrefix:='TJS';
  274. FWebIDLToPas.ClassSuffix:='';
  275. FWebIDLToPas.KeywordSuffix:='_';
  276. FWebIDLToPas.KeywordPrefix:='';
  277. FWebIDLToPas.DottedUnitsSupport:=dusFull;
  278. end;
  279. constructor TWebIDLToPasApplication.Create(TheOwner: TComponent);
  280. begin
  281. inherited Create(TheOwner);
  282. StopOnException:=True;
  283. ExceptionExitCode:=1;
  284. end;
  285. destructor TWebIDLToPasApplication.Destroy;
  286. begin
  287. FreeAndNil(FWebIDLToPas);
  288. inherited Destroy;
  289. end;
  290. procedure TWebIDLToPasApplication.WriteHelp(const Msg: string);
  291. begin
  292. {AllowWriteln}
  293. if (Msg<>'') then
  294. Writeln(StdErr,'Error : ',Msg);
  295. writeln(StdErr,'Usage: ', ExeName, ' [options]');
  296. Writeln(StdErr,'Where option is one or more of');
  297. Writeln(StdErr,'-h --help This help text.');
  298. Writeln(StdErr,'-a --private Write getters/setters as private methods. Default is protected.');
  299. Writeln(StdErr,'-c --constexternal Write consts as external const (no value).');
  300. Writeln(StdErr,'-d --dicttoclass[=Parent] Write dictionaries as classes.');
  301. Writeln(StdErr,'-e --expandunionargs Add overloads for all Union typed function arguments.');
  302. Writeln(StdErr,'-f --outputformat=[pas2js|wasmjob] Output format, default ',WebIDLToPasFormatNames[OutputFormat],'.');
  303. Writeln(StdErr,'-g --globals=list A comma separated list of global vars.');
  304. Writeln(StdErr,' Use @filename to load the globals from file.');
  305. Writeln(StdErr,' wasmjob: PasVarName=JSClassName,JOBRegisterName');
  306. Writeln(StdErr,'-i --input=FileName Input webidl file.');
  307. Writeln(StdErr,'-m --implementation=Filename include file as implementation.');
  308. Writeln(StdErr,'-n --include=Filename Include file at end of interface.');
  309. Writeln(StdErr,'-o --output=FileName Output file. Defaults to unit name with .pas extension appended.');
  310. Writeln(StdErr,'-p --optionsinheader Add options to header of generated file.');
  311. Writeln(StdErr,'-l --used=types A comma separated list of used IDL types. Only these types and necessary dependent types will be converted.');
  312. Writeln(StdErr,' use @filename to load the globals from file.');
  313. Writeln(StdErr,'-t --typealiases=alias A comma separated list of type aliases in Alias=Name form.');
  314. Writeln(StdErr,' use @filename to load the aliases from file.');
  315. Writeln(StdErr,'-u --unitname=Name name for unit. Defaults to input file without extension.');
  316. Writeln(StdErr,'-v --verbose Output some diagnostic information.');
  317. Writeln(StdErr,'-w --webidlversion=V Set web IDL version. Allowed values: v1 or v2.');
  318. Writeln(StdErr,'-x --extra=units Extra units to put in uses clause (comma separated list).');
  319. Writeln(StdErr,'-b --banned=list List of classes that may not be added to the final file (exclude e.g. window classes for workers)');
  320. ExitCode:=Ord(Msg<>'');
  321. {AllowWriteln-}
  322. end;
  323. var
  324. Application: TWebIDLToPasApplication;
  325. begin
  326. Application:=TWebIDLToPasApplication.Create(nil);
  327. Application.Title:='WebIDL To Pascal converter Application';
  328. Application.Run;
  329. Application.Free;
  330. end.