webidltopas.pp 45 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652
  1. {
  2. This file is part of the Free Component Library
  3. WEBIDL to pascal code converter
  4. Copyright (c) 2021 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. unit webidltopas;
  12. {$mode objfpc}{$H+}
  13. interface
  14. uses
  15. Classes, SysUtils, contnrs, WebIDLParser, WebIDLScanner, WebIDLDefs, pascodegen;
  16. Type
  17. { TPasData }
  18. TPasData = Class(TObject)
  19. private
  20. FPasName: String;
  21. Public
  22. IDL: TIDLBaseObject;
  23. Line, Column: integer;
  24. SrcFile: string;
  25. Resolved: TIDLDefinition;
  26. Constructor Create(APasName: String; D: TIDLBaseObject);
  27. Property PasName: String read FPasName;
  28. end;
  29. TPasDataClass = class of TPasData;
  30. TBaseConversionOption = (
  31. coAddOptionsToHeader,
  32. coExpandUnionTypeArgs,
  33. coDictionaryAsClass
  34. );
  35. TBaseConversionOptions = Set of TBaseConversionOption;
  36. const
  37. BaseConversionOptionName: array[TBaseConversionOption] of string = (
  38. 'AddOptionsToHeader',
  39. 'ExpandUnionTypeArgs',
  40. 'DictionaryAsClass'
  41. );
  42. type
  43. { TBaseWebIDLToPas }
  44. TBaseWebIDLToPas = Class(TPascalCodeGenerator)
  45. private
  46. FArrayPrefix: String;
  47. FArraySuffix: String;
  48. FAutoTypes: TStrings;
  49. FBaseOptions: TBaseConversionOptions;
  50. FClassPrefix: String;
  51. FClassSuffix: String;
  52. FContext: TWebIDLContext;
  53. FDictionaryClassParent: String;
  54. FFieldPrefix: String;
  55. FTypePrefix: String;
  56. FGetterPrefix: String;
  57. FIncludeImplementationCode: TStrings;
  58. FIncludeInterfaceCode: TStrings;
  59. FInputFileName: String;
  60. FGlobalDefs: TFPHashList;
  61. FOutputFileName: String;
  62. FPasDataClass: TPasDataClass;
  63. FPasNameList: TFPObjectList; // list TPasData
  64. FSetterPrefix: String;
  65. FTypeAliases: TStrings; // user defined type maping name to name
  66. FVerbose: Boolean;
  67. FWebIDLVersion: TWebIDLVersion;
  68. procedure SetIncludeImplementationCode(AValue: TStrings);
  69. procedure SetIncludeInterfaceCode(AValue: TStrings);
  70. procedure SetTypeAliases(AValue: TStrings);
  71. Protected
  72. procedure AddOptionsToHeader;
  73. Procedure Parse; virtual;
  74. Procedure WritePascal; virtual;
  75. function CreateParser(aContext: TWebIDLContext; S: TWebIDLScanner): TWebIDLParser; virtual;
  76. function CreateScanner(S: TStream): TWebIDLScanner; virtual;
  77. Function CreateContext: TWebIDLContext; virtual;
  78. // Auxiliary routines
  79. procedure GetOptions(L: TStrings; Full: boolean); virtual;
  80. procedure ProcessDefinitions; virtual;
  81. function CreatePasName(aName: String; D: TIDLBaseObject): TPasData; virtual;
  82. procedure AllocatePasNames(aList: TIDLDefinitionList; ParentName: String=''); virtual;
  83. function AllocatePasName(D: TIDLDefinition; ParentName: String=''): TPasData; virtual;
  84. procedure AddJSIdentifier(D: TIDLDefinition); virtual;
  85. procedure ResolveTypeDefs(aList: TIDLDefinitionList); virtual;
  86. procedure ResolveTypeDef(D: TIDLDefinition); virtual;
  87. function FindGlobalDef(const aName: UTF8String): TIDLDefinition; virtual;
  88. function GetDefPos(Def: TIDLBaseObject; WithoutFile: boolean = false): string; virtual;
  89. function GetPasDataPos(D: TPasData; WithoutFile: boolean = false): string; virtual;
  90. procedure EnsureUniqueNames(ML: TIDLDefinitionList); virtual;
  91. function AddSequenceDef(ST: TIDLSequenceTypeDefDefinition): Boolean; virtual;
  92. function GetName(ADef: TIDLDefinition): String; virtual;
  93. function GetPasClassName(const aName: string): string; overload; virtual;
  94. function GetTypeName(Const aTypeName: String; ForTypeDef: Boolean=False): String; overload; virtual;
  95. function GetTypeName(aTypeDef: TIDLTypeDefDefinition; ForTypeDef: Boolean=False): String; overload; virtual;
  96. function GetResolvedTypeName(Const aTypeName: String): String; overload; virtual;
  97. function GetSequenceTypeName(Seq: TIDLSequenceTypeDefDefinition; ForTypeDef: Boolean=False): string; virtual;
  98. function GetInterfaceDefHead(Intf: TIDLInterfaceDefinition): String; virtual;
  99. function GetDictionaryDefHead(const CurClassName: string; Dict: TIDLDictionaryDefinition): String; virtual;
  100. function CheckUnionTypeDefinition(D: TIDLDefinition): TIDLUnionTypeDefDefinition; virtual;
  101. procedure AddArgumentToOverloads(aList: TFPObjectlist; AName, ATypeName: String; PosEl: TIDLBaseObject); overload; virtual;
  102. procedure AddArgumentToOverloads(aList: TFPObjectlist; aDef: TIDLArgumentDefinition); overload; virtual;
  103. procedure AddUnionOverloads(aList: TFPObjectlist; AName: String; UT: TIDLUnionTypeDefDefinition); virtual;
  104. procedure AddOverloads(aList: TFPObjectlist; adef: TIDLFunctionDefinition; aIdx: Integer); virtual;
  105. function CloneNonPartialArgumentList(aList: TFPObjectlist; ADest: TFPObjectlist= Nil; AsPartial: Boolean=True): integer; virtual;
  106. function GetOverloads(aDef: TIDLFunctionDefinition): TFPObjectlist; virtual;
  107. function GetArguments(aList: TIDLDefinitionList; ForceBrackets: Boolean): String; virtual;
  108. function HaveConsts(aList: TIDLDefinitionList): Boolean; virtual;
  109. // Code generation routines. Return the number of actually written defs.
  110. function WriteFunctionImplicitTypes(aList: TIDLDefinitionList): Integer; virtual;
  111. function WriteAttributeImplicitTypes(aList: TIDLDefinitionList): Integer; virtual;
  112. function WriteOtherImplicitTypes(Intf: TIDLInterfaceDefinition; aMemberList: TIDLDefinitionList): Integer; virtual;
  113. function WriteDictionaryMemberImplicitTypes(aDict: TIDLDictionaryDefinition; aList: TIDLDefinitionList): Integer; virtual;
  114. function WriteCallBackDefs(aList: TIDLDefinitionList): Integer; virtual;
  115. function WriteDictionaryDefs(aList: TIDLDefinitionList): Integer; virtual;
  116. function WriteForwardClassDefs(aList: TIDLDefinitionList): Integer; virtual;
  117. function WriteInterfaceDefs(aList: TIDLDefinitionList): Integer; virtual;
  118. function WriteMethodDefs(aList: TIDLDefinitionList): Integer; virtual;
  119. function WriteUtilityMethods(Intf: TIDLInterfaceDefinition): Integer; virtual;
  120. function WriteTypeDefs(aList: TIDLDefinitionList): Integer; virtual;
  121. function WriteEnumDefs(aList: TIDLDefinitionList): Integer; virtual;
  122. function WriteConsts(aList: TIDLDefinitionList): Integer; virtual;
  123. function WriteProperties(aList: TIDLDefinitionList): Integer; virtual;
  124. function WritePlainFields(aList: TIDLDefinitionList): Integer; virtual;
  125. function WriteDictionaryFields(aList: TIDLDefinitionList): Integer; virtual;
  126. function WritePrivateReadOnlyFields(aList: TIDLDefinitionList): Integer; virtual;
  127. function WritePrivateGetters(aList: TIDLDefinitionList): Integer; virtual;
  128. function WritePrivateSetters(aList: TIDLDefinitionList): Integer; virtual;
  129. // Definitions. Return true if a definition was written.
  130. function WriteForwardClassDef(D: TIDLStructuredDefinition): Boolean; virtual;
  131. function WriteFunctionTypeDefinition(aDef: TIDLFunctionDefinition): Boolean; virtual;
  132. function WriteFunctionDefinition(aDef: TIDLFunctionDefinition): Boolean; virtual;
  133. function WriteTypeDef(aDef: TIDLTypeDefDefinition): Boolean; virtual;
  134. function WriteRecordDef(aDef: TIDLRecordDefinition): Boolean; virtual;
  135. function WriteEnumDef(aDef: TIDLEnumDefinition): Boolean; virtual;
  136. function WriteDictionaryField(aField: TIDLDictionaryMemberDefinition): Boolean; virtual;
  137. function WriteField(aAttr: TIDLAttributeDefinition): Boolean; virtual;
  138. function WriteConst(aConst: TIDLConstDefinition): Boolean ; virtual;
  139. function WriteInterfaceDef(Intf: TIDLInterfaceDefinition): Boolean; virtual;
  140. function WriteDictionaryDef(aDict: TIDLDictionaryDefinition): Boolean; virtual;
  141. // Additional
  142. procedure WriteAliasTypeDef(aDef: TIDLTypeDefDefinition); virtual;
  143. procedure WritePromiseDef(aDef: TIDLPromiseTypeDefDefinition); virtual;
  144. procedure WriteSequenceDef(aDef: TIDLSequenceTypeDefDefinition); virtual;
  145. procedure WriteUnionDef(aDef: TIDLUnionTypeDefDefinition); virtual;
  146. // Extra interface/Implementation code.
  147. procedure WriteImplementation; virtual;
  148. procedure WriteIncludeInterfaceCode; virtual;
  149. Property Context: TWebIDLContext Read FContext;
  150. Public
  151. constructor Create(TheOwner: TComponent); override;
  152. destructor Destroy; override;
  153. procedure Execute; virtual;
  154. procedure WriteOptions; virtual;
  155. Public
  156. Property InputFileName: String Read FInputFileName Write FInputFileName;
  157. Property OutputFileName: String Read FOutputFileName Write FOutputFileName;
  158. Property Verbose: Boolean Read FVerbose Write FVerbose;
  159. Property FieldPrefix: String Read FFieldPrefix Write FFieldPrefix;
  160. Property ClassPrefix: String Read FClassPrefix Write FClassPrefix;
  161. Property ClassSuffix: String Read FClassSuffix Write FClassSuffix;
  162. Property ArrayPrefix: String Read FArrayPrefix Write FArrayPrefix;
  163. Property ArraySuffix: String Read FArraySuffix Write FArraySuffix;
  164. Property GetterPrefix: String read FGetterPrefix write FGetterPrefix;
  165. Property SetterPrefix: String read FSetterPrefix write FSetterPrefix;
  166. Property TypePrefix: String read FTypePrefix write FTypePrefix;
  167. Property WebIDLVersion: TWebIDLVersion Read FWebIDLVersion Write FWebIDLVersion;
  168. Property TypeAliases: TStrings Read FTypeAliases Write SetTypeAliases;
  169. Property IncludeInterfaceCode: TStrings Read FIncludeInterfaceCode Write SetIncludeInterfaceCode;
  170. Property IncludeImplementationCode: TStrings Read FIncludeImplementationCode Write SetIncludeImplementationCode;
  171. Property DictionaryClassParent: String Read FDictionaryClassParent Write FDictionaryClassParent;
  172. Property BaseOptions: TBaseConversionOptions read FBaseOptions write FBaseOptions;
  173. Property PasDataClass: TPasDataClass read FPasDataClass write FPasDataClass;
  174. end;
  175. function BaseConversionOptionsToStr(Opts: TBaseConversionOptions): string;
  176. implementation
  177. uses typinfo;
  178. function BaseConversionOptionsToStr(Opts: TBaseConversionOptions): string;
  179. var
  180. o: TBaseConversionOption;
  181. begin
  182. Result:='';
  183. for o in Opts do
  184. begin
  185. if Result<>'' then Result:=Result+',';
  186. Result:=Result+BaseConversionOptionName[o];
  187. end;
  188. Result:='['+Result+']';
  189. end;
  190. { TPasData }
  191. constructor TPasData.Create(APasName: String; D: TIDLBaseObject);
  192. begin
  193. FPasName:=APasName;
  194. IDL:=D;
  195. SrcFile:=D.SrcFile;
  196. Line:=D.Line;
  197. Column:=D.Column;
  198. end;
  199. { TBaseWebIDLToPas }
  200. function TBaseWebIDLToPas.CreateContext: TWebIDLContext;
  201. begin
  202. Result:=TWebIDLContext.Create(True);
  203. end;
  204. function TBaseWebIDLToPas.CreateScanner(S: TStream): TWebIDLScanner;
  205. begin
  206. Result:=TWebIDLScanner.Create(S);
  207. end;
  208. function TBaseWebIDLToPas.CreateParser(aContext: TWebIDLContext;S: TWebIDLScanner): TWebIDLParser;
  209. begin
  210. Result:=TWebIDLParser.Create(aContext,S);
  211. Result.Version:=FWebIDLVersion;
  212. end;
  213. procedure TBaseWebIDLToPas.Parse;
  214. Var
  215. ms: TMemoryStream;
  216. S: TWebIDLScanner;
  217. P: TWebIDLParser;
  218. begin
  219. P:=Nil;
  220. ms:=TMemoryStream.Create;
  221. try
  222. ms.LoadFromFile(InputFileName);
  223. ms.Position:=0;
  224. S:=CreateScanner(ms);
  225. S.CurFile:=InputFileName;
  226. P:=CreateParser(Context,S);
  227. P.Parse;
  228. finally
  229. P.Free;
  230. S.Free;
  231. ms.Free;
  232. end;
  233. end;
  234. function TBaseWebIDLToPas.GetName(ADef: TIDLDefinition): String;
  235. begin
  236. If Assigned(ADef) and (TObject(ADef.Data) is TPasData) then
  237. Result:=TPasData(ADef.Data).PasName
  238. else
  239. Result:=ADef.Name;
  240. end;
  241. function TBaseWebIDLToPas.GetPasClassName(const aName: string): string;
  242. begin
  243. Result:=ClassPrefix+aName+ClassSuffix;
  244. end;
  245. function TBaseWebIDLToPas.HaveConsts(aList: TIDLDefinitionList): Boolean;
  246. Var
  247. D: TIDLDefinition;
  248. begin
  249. Result:=False;
  250. For D in aList do
  251. if D is TIDLConstDefinition then
  252. Exit(True);
  253. end;
  254. function TBaseWebIDLToPas.WriteFunctionImplicitTypes(aList: TIDLDefinitionList): Integer;
  255. Var
  256. D,D2,D3: TIDLDefinition;
  257. FD: TIDLFunctionDefinition absolute D;
  258. DA: TIDLArgumentDefinition absolute D2;
  259. UT: TIDLUnionTypeDefDefinition;
  260. begin
  261. Result:=0;
  262. for D in aList do
  263. if D is TIDLFunctionDefinition then
  264. if Not (foCallBack in FD.Options) then
  265. begin
  266. if (FD.ReturnType is TIDLSequenceTypeDefDefinition) then
  267. if AddSequenceDef(FD.ReturnType as TIDLSequenceTypeDefDefinition) then
  268. Inc(Result);
  269. For D2 in FD.Arguments do
  270. if (DA.ArgumentType is TIDLSequenceTypeDefDefinition) then
  271. begin
  272. if AddSequenceDef(DA.ArgumentType as TIDLSequenceTypeDefDefinition) then
  273. Inc(Result);
  274. end
  275. else
  276. begin
  277. UT:=CheckUnionTypeDefinition(DA.ArgumentType);
  278. if Assigned(UT) then
  279. For D3 in UT.Union do
  280. if (D3 is TIDLSequenceTypeDefDefinition) then
  281. if AddSequenceDef(D3 as TIDLSequenceTypeDefDefinition) then
  282. Inc(Result);
  283. end;
  284. end;
  285. if Result>0 then
  286. AddLn('');
  287. end;
  288. function TBaseWebIDLToPas.WriteAttributeImplicitTypes(aList: TIDLDefinitionList
  289. ): Integer;
  290. Var
  291. D: TIDLDefinition;
  292. FA: TIDLAttributeDefinition absolute D;
  293. begin
  294. Result:=0;
  295. for D in aList do
  296. if D is TIDLAttributeDefinition then
  297. if (FA.AttributeType is TIDLSequenceTypeDefDefinition) then
  298. if AddSequenceDef(FA.AttributeType as TIDLSequenceTypeDefDefinition) then
  299. Inc(Result);
  300. end;
  301. function TBaseWebIDLToPas.WriteOtherImplicitTypes(
  302. Intf: TIDLInterfaceDefinition; aMemberList: TIDLDefinitionList): Integer;
  303. begin
  304. Result:=0;
  305. if Intf=nil then ;
  306. if aMemberList=nil then ;
  307. end;
  308. function TBaseWebIDLToPas.WriteDictionaryMemberImplicitTypes(
  309. aDict: TIDLDictionaryDefinition; aList: TIDLDefinitionList): Integer;
  310. Var
  311. D: TIDLDefinition;
  312. FD: TIDLDictionaryMemberDefinition absolute D;
  313. begin
  314. Result:=0;
  315. if aDict=nil then ;
  316. for D in aList do
  317. if D is TIDLDictionaryMemberDefinition then
  318. if (FD.MemberType is TIDLSequenceTypeDefDefinition) then
  319. if AddSequenceDef(FD.MemberType as TIDLSequenceTypeDefDefinition) then
  320. Inc(Result);
  321. end;
  322. function TBaseWebIDLToPas.WritePrivateReadOnlyFields(aList: TIDLDefinitionList): Integer;
  323. begin
  324. Result:=0;
  325. if aList=nil then ;
  326. end;
  327. function TBaseWebIDLToPas.WritePrivateGetters(aList: TIDLDefinitionList
  328. ): Integer;
  329. begin
  330. Result:=0;
  331. if aList=nil then ;
  332. end;
  333. function TBaseWebIDLToPas.WritePrivateSetters(aList: TIDLDefinitionList
  334. ): Integer;
  335. begin
  336. Result:=0;
  337. if aList=nil then ;
  338. end;
  339. function TBaseWebIDLToPas.WriteProperties(aList: TIDLDefinitionList): Integer;
  340. begin
  341. Result:=0;
  342. if aList=nil then ;
  343. end;
  344. function TBaseWebIDLToPas.WriteConst(aConst: TIDLConstDefinition): Boolean;
  345. var
  346. S: UTF8String;
  347. begin
  348. Result:=true;
  349. S:=aConst.Value;
  350. if aConst.ConstType=ctInteger then
  351. S:=StringReplace(S,'0x','$',[]);
  352. Addln('%s = %s;',[GetName(aConst),S])
  353. end;
  354. function TBaseWebIDLToPas.WriteConsts(aList: TIDLDefinitionList): Integer;
  355. Var
  356. D: TIDLDefinition;
  357. begin
  358. EnsureSection(csConst);
  359. Indent;
  360. Result:=0;
  361. For D in aList do
  362. if D is TIDLConstDefinition then
  363. if WriteConst(D as TIDLConstDefinition) then
  364. Inc(Result);
  365. Undent;
  366. end;
  367. function TBaseWebIDLToPas.WritePlainFields(aList: TIDLDefinitionList): Integer;
  368. Var
  369. D: TIDLDefinition;
  370. A: TIDLAttributeDefinition absolute D;
  371. begin
  372. EnsureSection(csDeclaration);
  373. Result:=0;
  374. For D in aList do
  375. if D is TIDLAttributeDefinition then
  376. if Not (aoReadOnly in A.Options) then
  377. if WriteField(A) then
  378. Inc(Result);
  379. end;
  380. function TBaseWebIDLToPas.WriteDictionaryField(
  381. aField: TIDLDictionaryMemberDefinition): Boolean;
  382. Var
  383. Def,N,TN: String;
  384. begin
  385. Result:=True;
  386. N:=GetName(aField);
  387. TN:=GetTypeName(aField.MemberType);
  388. if TN='record' then
  389. TN:='TJSObject';
  390. if SameText(N,TN) then
  391. N:='_'+N;
  392. Def:=Format('%s: %s;',[N,TN]);
  393. if (N<>aField.Name) then
  394. Def:=Def+Format('external name ''%s'';',[aField.Name]);
  395. AddLn(Def);
  396. end;
  397. function TBaseWebIDLToPas.WriteDictionaryFields(aList: TIDLDefinitionList): Integer;
  398. Var
  399. D: TIDLDefinition;
  400. M: TIDLDictionaryMemberDefinition absolute D;
  401. begin
  402. Indent;
  403. Result:=0;
  404. For D in aList do
  405. if D is TIDLDictionaryMemberDefinition then
  406. if WriteDictionaryField(M) then
  407. Inc(Result);
  408. Undent;
  409. end;
  410. function TBaseWebIDLToPas.WriteMethodDefs(aList: TIDLDefinitionList): Integer;
  411. Var
  412. D: TIDLDefinition;
  413. FD: TIDLFunctionDefinition absolute D;
  414. begin
  415. Result:=0;
  416. for D in aList do
  417. if D is TIDLFunctionDefinition then
  418. if Not (foCallBack in FD.Options) then
  419. if WriteFunctionDefinition(FD) then
  420. Inc(Result);
  421. end;
  422. function TBaseWebIDLToPas.WriteUtilityMethods(Intf: TIDLInterfaceDefinition
  423. ): Integer;
  424. begin
  425. Result:=0;
  426. if Intf=nil then ;
  427. end;
  428. function TBaseWebIDLToPas.AddSequenceDef(ST: TIDLSequenceTypeDefDefinition
  429. ): Boolean;
  430. var
  431. TN: String;
  432. begin
  433. TN:=GetTypeName(ST);
  434. Result:=FAutoTypes.IndexOf(TN)=-1;
  435. if Result then
  436. begin
  437. FAutoTypes.Add(TN);
  438. DoLog('Automatically adding %s sequence definition for %s.',[TN,GetDefPos(ST)]);
  439. AddLn('%s = Array of %s;',[TN,GetTypeName(ST.ElementType)]);
  440. ST.Data:=CreatePasName(TN,ST);
  441. end;
  442. end;
  443. procedure TBaseWebIDLToPas.EnsureUniqueNames(ML: TIDLDefinitionList);
  444. Var
  445. L: TFPObjectHashTable;
  446. Procedure CheckRename(Def: TIDLDefinition);
  447. var
  448. I: integer;
  449. OrigName,BaseName,NewName: String;
  450. IsOverload: Boolean;
  451. CurDef , ConflictDef: TIDLDefinition;
  452. begin
  453. OrigName:=GetName(Def);
  454. BaseName:=LowerCase(OrigName);
  455. NewName:=BaseName;
  456. I:=0;
  457. IsOverload:=False;
  458. ConflictDef:=nil;
  459. Repeat
  460. CurDef:=TIDLDefinition(L.Items[NewName]);
  461. if (CurDef<>Nil) then
  462. // Overloads
  463. begin
  464. IsOverload:=((CurDef is TIDLFunctionDefinition) and (Def is TIDLFunctionDefinition));
  465. if IsOverload then
  466. CurDef:=Nil
  467. else
  468. begin
  469. ConflictDef:=CurDef;
  470. inc(I);
  471. if I>1 then
  472. raise EConvertError.Create('Duplicate identifier '+GetDefPos(Def)+' and '+GetDefPos(CurDef)+' (20220620073704)');
  473. NewName:=KeywordPrefix+BaseName+KeywordSuffix;
  474. OrigName:=KeywordPrefix+OrigName+KeywordSuffix;
  475. end;
  476. end;
  477. Until (CurDef=Nil);
  478. if (BaseName<>NewName) then
  479. begin
  480. BaseName:=GetName(Def);
  481. DoLog('Renaming duplicate identifier (%s) %s at %s to %s, other at %s',[Def.ClassName,BaseName,GetDefPos(Def),OrigName,GetDefPos(ConflictDef)]);
  482. // Original TPasName is in list, will be freed automatically
  483. Def.Data:=CreatePasName(OrigName,Def);
  484. end;
  485. if not IsOverload then
  486. L.Add(NewName,Def);
  487. end;
  488. var
  489. D: TIDLDefinition;
  490. begin
  491. L:=TFPObjectHashTable.Create(False);
  492. try
  493. For D in ML Do
  494. if not (D is TIDLConstDefinition) then
  495. CheckRename(D);
  496. For D in ML Do
  497. if (D is TIDLConstDefinition) then
  498. CheckRename(D);
  499. finally
  500. L.Free;
  501. end;
  502. end;
  503. function TBaseWebIDLToPas.WriteInterfaceDef(Intf: TIDLInterfaceDefinition): Boolean;
  504. Var
  505. aClassName: String;
  506. Decl: String;
  507. ML: TIDLDefinitionList;
  508. begin
  509. Result:=True;
  510. ML:=TIDLDefinitionList.Create(Nil,False);
  511. try
  512. Intf.GetFullMemberList(ML);
  513. EnsureUniqueNames(ML);
  514. aClassName:=GetName(Intf);
  515. // class comment
  516. ClassComment(aClassName);
  517. // sub types
  518. WriteFunctionImplicitTypes(ML);
  519. WriteAttributeImplicitTypes(ML);
  520. WriteOtherImplicitTypes(Intf,ML);
  521. // class and ancestor
  522. Decl:=aClassName+' = '+GetInterfaceDefHead(Intf);
  523. AddLn(Decl);
  524. // private section
  525. AddLn('Private');
  526. Indent;
  527. WritePrivateReadOnlyFields(ML);
  528. WritePrivateGetters(ML);
  529. WritePrivateSetters(ML);
  530. Undent;
  531. // write public section
  532. AddLn('Public');
  533. if HaveConsts(ML) then
  534. begin
  535. Indent;
  536. PushSection(csUnknown);
  537. WriteConsts(ML);
  538. PopSection;
  539. Undent;
  540. AddLn('Public');
  541. end;
  542. Indent;
  543. WritePlainFields(ML);
  544. WriteMethodDefs(ML);
  545. WriteUtilityMethods(Intf);
  546. WriteProperties(ML);
  547. Undent;
  548. AddLn('end;');
  549. finally
  550. ML.Free;
  551. end;
  552. end;
  553. function TBaseWebIDLToPas.WriteDictionaryDef(aDict: TIDLDictionaryDefinition
  554. ): Boolean;
  555. Var
  556. CurClassName, Decl: String;
  557. DefList: TIDLDefinitionList;
  558. CurDefs: TIDLDictionaryDefinition;
  559. begin
  560. Result:=True;
  561. DefList:=TIDLDefinitionList.Create(Nil,False);
  562. try
  563. CurDefs:=aDict;
  564. While CurDefs<>Nil do
  565. begin
  566. CurDefs.GetFullMemberList(DefList);
  567. CurDefs:=CurDefs.ParentDictionary;
  568. end;
  569. CurClassName:=GetName(aDict);
  570. ClassComment(CurClassName);
  571. WriteDictionaryMemberImplicitTypes(aDict, DefList);
  572. // class and ancestor
  573. Decl:=GetDictionaryDefHead(CurClassName,aDict);
  574. AddLn(Decl);
  575. WriteDictionaryFields(DefList);
  576. AddLn('end;');
  577. finally
  578. DefList.Free;
  579. end;
  580. end;
  581. constructor TBaseWebIDLToPas.Create(TheOwner: TComponent);
  582. begin
  583. inherited Create(TheOwner);
  584. WebIDLVersion:=v2;
  585. FieldPrefix:='F';
  586. ClassPrefix:='T';
  587. ClassSuffix:='';
  588. ArrayPrefix:='T';
  589. ArraySuffix:='DynArray';
  590. GetterPrefix:='Get';
  591. SetterPrefix:='Set';
  592. TypePrefix:='T';
  593. FTypeAliases:=TStringList.Create;
  594. FPasNameList:=TFPObjectList.Create(True);
  595. FPasDataClass:=TPasData;
  596. FAutoTypes:=TStringList.Create;
  597. FIncludeInterfaceCode:=TStringList.Create;
  598. FIncludeImplementationCode:=TStringList.Create;
  599. FGlobalDefs:=TFPHashList.Create;
  600. end;
  601. destructor TBaseWebIDLToPas.Destroy;
  602. begin
  603. FreeAndNil(FGlobalDefs);
  604. FreeAndNil(FIncludeInterfaceCode);
  605. FreeAndNil(FIncludeImplementationCode);
  606. FreeAndNil(FAutoTypes);
  607. FreeAndNil(FTypeAliases);
  608. FreeAndNil(FPasNameList);
  609. inherited Destroy;
  610. end;
  611. procedure TBaseWebIDLToPas.WriteImplementation;
  612. Var
  613. S: String;
  614. begin
  615. Addln('');
  616. For S in FIncludeImplementationCode do
  617. Addln(S);
  618. Addln('');
  619. end;
  620. function TBaseWebIDLToPas.GetTypeName(aTypeDef: TIDLTypeDefDefinition; ForTypeDef: Boolean = False): String;
  621. begin
  622. if ATypeDef is TIDLSequenceTypeDefDefinition then
  623. begin
  624. if Assigned(aTypeDef.Data) then
  625. Result:=GetName(aTypeDef)
  626. else
  627. Result:=GetSequenceTypeName(TIDLSequenceTypeDefDefinition(aTypeDef),ForTypeDef);
  628. end
  629. else
  630. Result:=GetTypeName(aTypeDef.TypeName,ForTypeDef);
  631. end;
  632. function TBaseWebIDLToPas.GetResolvedTypeName(const aTypeName: String): String;
  633. var
  634. aDef: TIDLDefinition;
  635. begin
  636. aDef:=FindGlobalDef(aTypeName);
  637. if aDef is TIDLTypeDefDefinition then
  638. Result:=GetResolvedTypeName(TIDLTypeDefDefinition(aDef).TypeName)
  639. else
  640. Result:=GetTypeName(aTypeName);
  641. end;
  642. function TBaseWebIDLToPas.GetSequenceTypeName(
  643. Seq: TIDLSequenceTypeDefDefinition; ForTypeDef: Boolean): string;
  644. begin
  645. //writeln('TBaseWebIDLToPas.GetSequenceTypeName ',Seq.ElementType.Name,' ',Seq.ElementType.TypeName);
  646. Result:=GetTypeName(Seq.ElementType,ForTypeDef);
  647. if Result='' then
  648. raise EConvertError.Create('sequence without name at '+GetDefPos(Seq));
  649. if LeftStr(Result,length(ArrayPrefix))<>ArrayPrefix then
  650. Result:=ArrayPrefix+Result;
  651. Result:=Result+ArraySuffix;
  652. end;
  653. function TBaseWebIDLToPas.GetInterfaceDefHead(Intf: TIDLInterfaceDefinition
  654. ): String;
  655. begin
  656. Result:='class';
  657. if Intf=nil then ;
  658. end;
  659. function TBaseWebIDLToPas.GetDictionaryDefHead(const CurClassName: string;
  660. Dict: TIDLDictionaryDefinition): String;
  661. var
  662. CurParent: String;
  663. begin
  664. if Dict=nil then ;
  665. if (coDictionaryAsClass in BaseOptions) then
  666. begin
  667. CurParent:=DictionaryClassParent;
  668. if CurParent='' then
  669. CurParent:='TJSObject';
  670. Result:='class('+CurParent+')'
  671. end
  672. else
  673. Result:='record';
  674. Result:=CurClassName+' = '+Result;
  675. end;
  676. function TBaseWebIDLToPas.GetTypeName(const aTypeName: String; ForTypeDef: Boolean
  677. ): String;
  678. Var
  679. A: UTF8String;
  680. D: TIDLDefinition;
  681. begin
  682. Case aTypeName of
  683. 'boolean': Result:='Boolean';
  684. 'byte': Result:='ShortInt';
  685. 'octet': Result:='Byte';
  686. 'short': Result:='SmallInt';
  687. 'unsigned short': Result:='Word';
  688. 'long': Result:='Integer';
  689. 'unsigned long': Result:='LongWord';
  690. 'long long': Result:='Int64';
  691. 'unsigned long long': Result:='QWord';
  692. 'float',
  693. 'unrestricted float': Result:='Single';
  694. 'double',
  695. 'unrestricted double': Result:='Double';
  696. 'union',
  697. 'any': Result:='JSValue';
  698. 'DOMString',
  699. 'USVString',
  700. 'ByteString': Result:='UnicodeString';
  701. 'record',
  702. 'object': Result:=GetPasClassName('Object');
  703. 'Error',
  704. 'DOMException': Result:=GetPasClassName('Error');
  705. 'ArrayBuffer',
  706. 'DataView',
  707. 'Int8Array',
  708. 'Int16Array',
  709. 'Int32Array',
  710. 'Uint8Array',
  711. 'Uint16Array',
  712. 'Uint32Array',
  713. 'Uint8ClampedArray',
  714. 'Float32Array',
  715. 'Float64Array': Result:=GetPasClassName(aTypeName);
  716. 'void': Result:=aTypeName;
  717. else
  718. if ForTypeDef then ;
  719. Result:=aTypeName;
  720. D:=FContext.FindDefinition(Result);
  721. if D<>Nil then
  722. Result:=GetName(D)
  723. else
  724. begin
  725. A:=FTypeAliases.Values[Result];
  726. If (A<>'') then
  727. Result:=A;
  728. end;
  729. end;
  730. end;
  731. function TBaseWebIDLToPas.WriteField(aAttr: TIDLAttributeDefinition): Boolean;
  732. begin
  733. Result:=false;
  734. if aAttr=nil then ;
  735. end;
  736. function TBaseWebIDLToPas.WriteForwardClassDef(D: TIDLStructuredDefinition): Boolean;
  737. begin
  738. Result:=not D.IsPartial;
  739. if Result then
  740. AddLn('%s = Class;',[GetName(D)]);
  741. end;
  742. function TBaseWebIDLToPas.WriteForwardClassDefs(aList: TIDLDefinitionList): Integer;
  743. Var
  744. D: TIDLDefinition;
  745. begin
  746. Result:=0;
  747. Comment('Forward class definitions');
  748. For D in aList do
  749. if D is TIDLInterfaceDefinition then
  750. if WriteForwardClassDef(D as TIDLInterfaceDefinition) then
  751. Inc(Result);
  752. if coDictionaryAsClass in BaseOptions then
  753. For D in aList do
  754. if D is TIDLDictionaryDefinition then
  755. if WriteForwardClassDef(D as TIDLDictionaryDefinition) then
  756. Inc(Result);
  757. end;
  758. procedure TBaseWebIDLToPas.WriteSequenceDef(aDef: TIDLSequenceTypeDefDefinition);
  759. begin
  760. Addln('%s = array of %s;',[GetName(aDef),GetTypeName(aDef.ElementType)])
  761. end;
  762. procedure TBaseWebIDLToPas.WriteUnionDef(aDef: TIDLUnionTypeDefDefinition);
  763. Var
  764. S: UTF8String;
  765. D: TIDLDefinition;
  766. begin
  767. S:='';
  768. For D in adef.Union do
  769. begin
  770. if (S<>'') then
  771. S:=S+', ';
  772. S:=S+(D as TIDLTypeDefDefinition).TypeName;
  773. end;
  774. Comment('Union of '+S);
  775. AddLn('%s = JSValue; ',[GetName(aDef)])
  776. end;
  777. procedure TBaseWebIDLToPas.WritePromiseDef(aDef: TIDLPromiseTypeDefDefinition);
  778. begin
  779. AddLn('%s = TJSPromise;',[GetName(aDef)]);
  780. end;
  781. procedure TBaseWebIDLToPas.WriteAliasTypeDef(aDef: TIDLTypeDefDefinition);
  782. Var
  783. TN: String;
  784. begin
  785. TN:=GetTypeName(aDef,True);
  786. AddLn('%s = %s;',[GetName(aDef),TN]);
  787. end;
  788. function TBaseWebIDLToPas.WriteTypeDef(aDef: TIDLTypeDefDefinition): Boolean;
  789. begin
  790. Result:=True;
  791. if ADef is TIDLSequenceTypeDefDefinition then
  792. WriteSequenceDef(aDef as TIDLSequenceTypeDefDefinition)
  793. else if ADef is TIDLUnionTypeDefDefinition then
  794. WriteUnionDef(aDef as TIDLUnionTypeDefDefinition)
  795. else if ADef is TIDLPromiseTypeDefDefinition then
  796. WritePromiseDef(aDef as TIDLPromiseTypeDefDefinition)
  797. else if ADef is TIDLRecordDefinition then
  798. WriteRecordDef(aDef as TIDLRecordDefinition)
  799. else
  800. WriteAliasTypeDef(aDef);
  801. end;
  802. function TBaseWebIDLToPas.WriteRecordDef(aDef: TIDLRecordDefinition): Boolean;
  803. Var
  804. KT,VT: String;
  805. begin
  806. Result:=True;
  807. KT:=GetTypeName(aDef.KeyType);
  808. VT:=GetTypeName(aDef.ValueType);
  809. AddLn('%s = Class(TJSObject)',[GetName(aDef)]);
  810. AddLn('private');
  811. Indent;
  812. AddLn('function GetValue(aKey: %s): %s; external name ''[]'';',[KT,VT]);
  813. AddLn('procedure SetValue(aKey: %s; const AValue: %s); external name ''[]'';',[KT,VT]);
  814. Undent;
  815. AddLn('public');
  816. Indent;
  817. AddLn('property Values[Name: %s]: %s read GetProperties write SetProperties; default;',[KT,VT]);
  818. Undent;
  819. AddLn('end;');
  820. end;
  821. function TBaseWebIDLToPas.WriteTypeDefs(aList: TIDLDefinitionList): Integer;
  822. Var
  823. D: TIDLDefinition;
  824. TD: TIDLTypeDefDefinition absolute D;
  825. begin
  826. Result:=0;
  827. EnsureSection(csType);
  828. for D in aList do
  829. if D is TIDLTypeDefDefinition then
  830. if WriteTypeDef(TD) then
  831. Inc(Result);
  832. end;
  833. function TBaseWebIDLToPas.WriteEnumDef(aDef: TIDLEnumDefinition): Boolean;
  834. begin
  835. Result:=True;
  836. AddLn('%s = String;',[GetName(aDef)]);
  837. end;
  838. function TBaseWebIDLToPas.WriteEnumDefs(aList: TIDLDefinitionList): Integer;
  839. Var
  840. D: TIDLDefinition;
  841. ED: TIDLEnumDefinition absolute D;
  842. begin
  843. Result:=0;
  844. EnsureSection(csType);
  845. for D in aList do
  846. if D is TIDLEnumDefinition then
  847. if WriteEnumDef(ED) then
  848. Inc(Result);
  849. end;
  850. function TBaseWebIDLToPas.GetArguments(aList: TIDLDefinitionList;
  851. ForceBrackets: Boolean): String;
  852. Var
  853. I, Def: TIDLDefinition;
  854. A: TIDLArgumentDefinition absolute I;
  855. Arg, aTypeName: string;
  856. begin
  857. Result:='';
  858. For I in aList do
  859. begin
  860. Arg:=GetName(A);
  861. aTypeName:=GetTypeName(A.ArgumentType);
  862. Arg:=Arg+': '+aTypeName;
  863. Def:=FindGlobalDef(A.ArgumentType.TypeName);
  864. //writeln('TBaseWebIDLToPas.GetArguments Arg="',Arg,'" A.ArgumentType.TypeName=',A.ArgumentType.TypeName,' ',Def<>nil);
  865. if (Def is TIDLFunctionDefinition)
  866. or (Def is TIDLDictionaryDefinition)
  867. or (A.ArgumentType.TypeName='sequence')
  868. or SameText(aTypeName,'UnicodeString') then
  869. Arg:='const '+Arg;
  870. if Result<>'' then
  871. Result:=Result+'; ';
  872. Result:=Result+Arg;
  873. end;
  874. if (Result<>'') or ForceBrackets then
  875. Result:='('+Result+')';
  876. end;
  877. Type
  878. // A partial argument list is a list which has been generated for a optional argument.
  879. // Additional arguments can never be added to a partial list...
  880. TIDLPartialDefinitionList = Class(TIDLDefinitionList);
  881. function TBaseWebIDLToPas.CloneNonPartialArgumentList(aList: TFPObjectlist;
  882. ADest: TFPObjectlist; AsPartial: Boolean): integer;
  883. Var
  884. I,J: Integer;
  885. CD: TIDLDefinition;
  886. DL,CL: TIDLDefinitionList;
  887. begin
  888. Result:=0;
  889. if ADest=Nil then
  890. ADest:=aList;
  891. I:=aList.Count-1;
  892. While (I>=0) do
  893. begin
  894. DL:=TIDLDefinitionList(alist[i]);
  895. if Not (DL is TIDLPartialDefinitionList) then
  896. begin
  897. Inc(Result);
  898. if AsPartial then
  899. CL:=TIDLPartialDefinitionList.Create(Nil,True)
  900. else
  901. CL:=TIDLDefinitionList.Create(Nil,True);
  902. aDest.Add(CL);
  903. For J:=0 to DL.Count-1 do
  904. begin
  905. CD:=(DL.Definitions[J] as TIDLArgumentDefinition).Clone(Nil);
  906. CL.Add(CD);
  907. AllocatePasName(CD);
  908. end;
  909. end;
  910. Dec(I);
  911. end;
  912. end;
  913. procedure TBaseWebIDLToPas.AddArgumentToOverloads(aList: TFPObjectlist; AName,
  914. ATypeName: String; PosEl: TIDLBaseObject);
  915. Var
  916. I: Integer;
  917. CD: TIDLArgumentDefinition;
  918. DL: TIDLDefinitionList;
  919. begin
  920. For I:=0 to aList.Count-1 do
  921. begin
  922. DL:=TIDLDefinitionList(alist[i]);
  923. if Not (DL is TIDLPartialDefinitionList) then
  924. begin
  925. CD:=TIDLArgumentDefinition.Create(Nil,aName,PosEl.SrcFile,PosEl.Line,PosEl.Column);
  926. CD.ArgumentType:=TIDLTypeDefDefinition.Create(CD,'',PosEl.SrcFile,PosEl.Line,PosEl.Column);
  927. CD.ArgumentType.TypeName:=aTypeName;
  928. DL.Add(CD);
  929. AllocatePasName(cd,'');
  930. end;
  931. end;
  932. end;
  933. procedure TBaseWebIDLToPas.AddArgumentToOverloads(aList: TFPObjectlist; aDef: TIDLArgumentDefinition);
  934. Var
  935. I: Integer;
  936. CD: TIDLDefinition;
  937. DL: TIDLDefinitionList;
  938. begin
  939. For I:=0 to aList.Count-1 do
  940. begin
  941. DL:=TIDLDefinitionList(aList[i]);
  942. if Not (DL is TIDLPartialDefinitionList) then
  943. begin
  944. CD:=aDef.Clone(Nil);
  945. DL.Add(CD);
  946. if aDef.Data<>Nil then
  947. CD.Data:=CreatePasName(TPasData(aDef.Data).PasName,CD)
  948. else
  949. AllocatePasName(cd,'');
  950. end;
  951. end;
  952. end;
  953. procedure TBaseWebIDLToPas.AddUnionOverloads(aList: TFPObjectlist; AName: String; UT: TIDLUnionTypeDefDefinition);
  954. Var
  955. L,L2: TFPObjectList;
  956. I,J: Integer;
  957. D: TIDLDefinitionList;
  958. Dups: TStringList;
  959. begin
  960. L2:=Nil;
  961. Dups:=TStringList.Create;
  962. Dups.Sorted:=True;
  963. Dups.Duplicates:=dupIgnore;
  964. L:=TFPObjectList.Create(False);
  965. try
  966. L2:=TFPObjectList.Create(False);
  967. // Collect non partial argument lists
  968. for I:=0 to aList.Count-1 do
  969. begin
  970. D:=TIDLDefinitionList(aList[i]);
  971. if Not (D is TIDLPartialDefinitionList) then
  972. L.Add(D);
  973. end;
  974. // Collect unique pascal types. Note that this can reduce the list to 1 element...
  975. For I:=0 to UT.Union.Count-1 do
  976. Dups.Add(GetTypeName(UT.Union[I] as TIDLTypeDefDefinition));
  977. // First, clone list and add argument to cloned lists
  978. For I:=1 to Dups.Count-1 do
  979. begin
  980. // Clone list
  981. CloneNonPartialArgumentList(L,L2,False);
  982. // Add argument to cloned list
  983. AddArgumentToOverloads(L2,aName,Dups[i],UT.Union[I]);
  984. // Add overloads to original list
  985. For J:=0 to L2.Count-1 do
  986. aList.Add(L2[J]);
  987. L2.Clear;
  988. end;
  989. // Add first Union to original list
  990. AddArgumentToOverloads(L,aName,Dups[0],UT.Union[0]);
  991. finally
  992. Dups.Free;
  993. L2.Free;
  994. L.Free;
  995. end;
  996. end;
  997. function TBaseWebIDLToPas.CheckUnionTypeDefinition(D: TIDLDefinition
  998. ): TIDLUnionTypeDefDefinition;
  999. begin
  1000. Result:=Nil;
  1001. If (D is TIDLUnionTypeDefDefinition) then
  1002. Result:=D as TIDLUnionTypeDefDefinition
  1003. else
  1004. begin
  1005. D:=Context.FindDefinition((D as TIDLTypeDefDefinition).TypeName);
  1006. if (D is TIDLUnionTypeDefDefinition) then
  1007. Result:=D as TIDLUnionTypeDefDefinition
  1008. end
  1009. end;
  1010. procedure TBaseWebIDLToPas.AddOverloads(aList: TFPObjectlist;
  1011. adef: TIDLFunctionDefinition; aIdx: Integer);
  1012. Var
  1013. Arg: TIDLArgumentDefinition;
  1014. D: TIDLDefinition;
  1015. UT: TIDLUnionTypeDefDefinition;
  1016. begin
  1017. if aIdx>=ADef.Arguments.Count then
  1018. exit;
  1019. Arg:=ADef.Argument[aIdx];
  1020. if Arg.IsOptional then
  1021. CloneNonPartialArgumentList(aList);
  1022. // Add current to list.
  1023. D:=Arg.ArgumentType;
  1024. UT:=Nil;
  1025. if coExpandUnionTypeArgs in BaseOptions then
  1026. UT:=CheckUnionTypeDefinition(D);
  1027. if UT=Nil then
  1028. AddArgumentToOverloads(aList,Arg)
  1029. else
  1030. AddUnionOverLoads(aList,Arg.Name,UT);
  1031. AddOverloads(aList,aDef,aIdx+1);
  1032. end;
  1033. function TBaseWebIDLToPas.GetOverloads(aDef: TIDLFunctionDefinition): TFPObjectlist;
  1034. begin
  1035. Result:=TFPObjectList.Create;
  1036. try
  1037. Result.Add(TIDLDefinitionList.Create(Nil,True));
  1038. AddOverloads(Result,adef,0);
  1039. except
  1040. Result.Free;
  1041. Raise;
  1042. end;
  1043. end;
  1044. function TBaseWebIDLToPas.WriteFunctionTypeDefinition(aDef: TIDLFunctionDefinition): Boolean;
  1045. Var
  1046. FN,RT,Args: String;
  1047. begin
  1048. Result:=True;
  1049. FN:=GetName(aDef);
  1050. RT:=GetTypeName(aDef.ReturnType,False);
  1051. if (RT='void') then
  1052. RT:='';
  1053. Args:=GetArguments(aDef.Arguments,False);
  1054. if (RT='') then
  1055. AddLn('%s = procedure %s;',[FN,Args])
  1056. else
  1057. AddLn('%s = function %s: %s;',[FN,Args,RT])
  1058. end;
  1059. function TBaseWebIDLToPas.WriteFunctionDefinition(aDef: TIDLFunctionDefinition): Boolean;
  1060. begin
  1061. Result:=true;
  1062. if aDef=nil then exit;
  1063. end;
  1064. function TBaseWebIDLToPas.WriteCallBackDefs(aList: TIDLDefinitionList): Integer;
  1065. Var
  1066. D: TIDLDefinition;
  1067. FD: TIDLFunctionDefinition absolute D;
  1068. begin
  1069. Result:=0;
  1070. EnsureSection(csType);
  1071. for D in aList do
  1072. if D is TIDLFunctionDefinition then
  1073. if (foCallBack in FD.Options) then
  1074. if WriteFunctionTypeDefinition(FD) then
  1075. Inc(Result);
  1076. end;
  1077. function TBaseWebIDLToPas.WriteDictionaryDefs(aList: TIDLDefinitionList): Integer;
  1078. Var
  1079. D: TIDLDefinition;
  1080. DD: TIDLDictionaryDefinition absolute D;
  1081. begin
  1082. Result:=0;
  1083. EnsureSection(csType);
  1084. for D in aList do
  1085. if D is TIDLDictionaryDefinition then
  1086. if not TIDLDictionaryDefinition(D).IsPartial then
  1087. if WriteDictionaryDef(DD) then
  1088. Inc(Result);
  1089. end;
  1090. function TBaseWebIDLToPas.WriteInterfaceDefs(aList: TIDLDefinitionList): Integer;
  1091. Var
  1092. D: TIDLDefinition;
  1093. ID: TIDLInterfaceDefinition absolute D;
  1094. begin
  1095. Result:=0;
  1096. EnsureSection(csType);
  1097. for D in aList do
  1098. if D is TIDLInterfaceDefinition then
  1099. if not TIDLInterfaceDefinition(D).IsPartial then
  1100. if WriteInterfaceDef(ID) then
  1101. Inc(Result);
  1102. end;
  1103. procedure TBaseWebIDLToPas.GetOptions(L: TStrings; Full: boolean);
  1104. function CountLines(const s: string): integer;
  1105. var
  1106. p: Integer;
  1107. begin
  1108. Result:=1;
  1109. p:=1;
  1110. while p<=length(s) do
  1111. case s[p] of
  1112. #10:
  1113. begin
  1114. inc(p);
  1115. inc(Result);
  1116. end;
  1117. #13:
  1118. begin
  1119. inc(p);
  1120. inc(Result);
  1121. if (p<=length(s)) and (s[p]=#10) then inc(p);
  1122. end;
  1123. else
  1124. inc(p);
  1125. end;
  1126. end;
  1127. function CodeInfo(Src: TStrings): string;
  1128. var
  1129. LineCount, i: Integer;
  1130. begin
  1131. Result:='';
  1132. if Src.Count=0 then
  1133. exit;
  1134. LineCount:=0;
  1135. for i:=0 to Src.Count-1 do
  1136. inc(LineCount,CountLines(Src[i]));
  1137. Result:=Result+IntToStr(Src.Count)+' chunks in '+IntToStr(LineCount)+' lines';
  1138. end;
  1139. Var
  1140. S: String;
  1141. I: Integer;
  1142. begin
  1143. L.Add('Used command-line options: ');
  1144. For I:=1 to ParamCount do
  1145. L.Add(ParamStr(i));
  1146. L.Add('');
  1147. L.Add('Command-line options translated to: ');
  1148. L.Add('');
  1149. if Full then
  1150. begin
  1151. L.Add('Verbose: '+BoolToStr(Verbose,true));
  1152. L.Add('Converter: '+ClassName);
  1153. L.Add('InputFileName: '+InputFileName);
  1154. L.Add('OutputFileName: '+OutputFileName);
  1155. end;
  1156. L.Add('Keyword prefix: '+KeywordPrefix);
  1157. L.Add('Keyword suffix: '+KeywordSuffix);
  1158. L.Add('Class prefix: '+ClassPrefix);
  1159. L.Add('Class suffix: '+ClassSuffix);
  1160. L.Add('Field prefix: '+FieldPrefix);
  1161. L.Add('Getter prefix: '+GetterPrefix);
  1162. L.Add('Setter prefix: '+SetterPrefix);
  1163. Str(WebIDLVersion,S);
  1164. L.Add('WebIDL version: '+S);
  1165. if TypeAliases.Count>0 then
  1166. begin
  1167. L.Add('Type aliases:');
  1168. L.AddStrings(Self.TypeAliases);
  1169. end;
  1170. L.Add('Dictionary class parent: '+DictionaryClassParent);
  1171. if Full then
  1172. begin
  1173. L.Add('Include interface code: '+CodeInfo(IncludeInterfaceCode));
  1174. L.Add('Include implementation code: '+CodeInfo(IncludeImplementationCode));
  1175. end;
  1176. L.Add('Base Options: '+BaseConversionOptionsToStr(BaseOptions));
  1177. end;
  1178. procedure TBaseWebIDLToPas.AddOptionsToHeader;
  1179. Var
  1180. L: TStrings;
  1181. begin
  1182. L:=TStringList.Create;
  1183. try
  1184. L.Add('Automatically generated file by '+ClassName+' on '+FormatDateTime('yyyy-mm-dd hh:nn:ss',Now));
  1185. L.Add('');
  1186. GetOptions(L,false);
  1187. Comment(L);
  1188. finally
  1189. L.Free;
  1190. end;
  1191. end;
  1192. procedure TBaseWebIDLToPas.WriteIncludeInterfaceCode;
  1193. Var
  1194. S: String;
  1195. begin
  1196. For S in IncludeInterfaceCode do
  1197. Addln(S);
  1198. end;
  1199. procedure TBaseWebIDLToPas.WritePascal;
  1200. begin
  1201. CreateUnitClause;
  1202. CreateHeader;
  1203. if coAddOptionsToHeader in BaseOptions then
  1204. AddOptionsToHeader;
  1205. EnsureSection(csType);
  1206. Indent;
  1207. WriteForwardClassDefs(Context.Definitions);
  1208. WriteEnumDefs(Context.Definitions);
  1209. WriteTypeDefs(Context.Definitions);
  1210. WriteCallbackDefs(Context.Definitions);
  1211. WriteDictionaryDefs(Context.Definitions);
  1212. WriteInterfaceDefs(Context.Definitions);
  1213. Undent;
  1214. WriteIncludeInterfaceCode;
  1215. Addln('');
  1216. AddLn('implementation');
  1217. WriteImplementation;
  1218. AddLn('end.');
  1219. Source.SaveToFile(OutputFileName);
  1220. end;
  1221. function TBaseWebIDLToPas.CreatePasName(aName: String; D: TIDLBaseObject
  1222. ): TPasData;
  1223. begin
  1224. Result:=PasDataClass.Create(EscapeKeyWord(aName),D);
  1225. FPasNameList.Add(Result);
  1226. end;
  1227. function TBaseWebIDLToPas.AllocatePasName(D: TIDLDefinition; ParentName: String): TPasData;
  1228. Var
  1229. CN: String;
  1230. aData: TPasData;
  1231. begin
  1232. //writeln('TBaseWebIDLToPas.AllocatePasName ',ParentName,'.',D.Name,':',D.ClassName);
  1233. CN:=D.Name;
  1234. if D Is TIDLInterfaceDefinition then
  1235. begin
  1236. if not TIDLInterfaceDefinition(D).IsPartial then
  1237. AddJSIdentifier(D);
  1238. CN:=ClassPrefix+CN+ClassSuffix;
  1239. Result:=CreatePasName(CN,D);
  1240. D.Data:=Result;
  1241. AllocatePasNames((D as TIDLInterfaceDefinition).Members,D.Name);
  1242. end
  1243. else if D Is TIDLDictionaryDefinition then
  1244. begin
  1245. if not TIDLDictionaryDefinition(D).IsPartial then
  1246. AddJSIdentifier(D);
  1247. if coDictionaryAsClass in BaseOptions then
  1248. CN:=ClassPrefix+CN+ClassSuffix;
  1249. Result:=CreatePasName(EscapeKeyWord(CN),D);
  1250. D.Data:=Result;
  1251. AllocatePasNames((D as TIDLDictionaryDefinition).Members,D.Name);
  1252. end
  1253. else
  1254. begin
  1255. if (D is TIDLTypeDefDefinition)
  1256. or ((D Is TIDLFunctionDefinition) and (foCallBack in TIDLFunctionDefinition(D).Options)) then
  1257. begin
  1258. CN:=TypePrefix+CN;
  1259. AddJSIdentifier(D);
  1260. end;
  1261. Result:=CreatePasName(CN,D);
  1262. D.Data:=Result;
  1263. if D Is TIDLFunctionDefinition then
  1264. AllocatePasNames((D as TIDLFunctionDefinition).Arguments,D.Name);
  1265. end;
  1266. aData:=TPasData(D.Data);
  1267. if Verbose and (aData.PasName<>D.Name) then
  1268. begin
  1269. if (ParentName<>'') then
  1270. ParentName:=ParentName+'.';
  1271. DoLog('Renamed %s to %s for %s',[ParentName+D.Name,aData.PasName,GetPasDataPos(aData)]);
  1272. end;
  1273. end;
  1274. procedure TBaseWebIDLToPas.AddJSIdentifier(D: TIDLDefinition);
  1275. var
  1276. Old: TIDLDefinition;
  1277. begin
  1278. //writeln('TBaseWebIDLToPas.AddJSIdentifier ',D.Name,':',D.ClassName);
  1279. if (D.Parent=nil)
  1280. or ((D is TIDLInterfaceDefinition) and TIDLInterfaceDefinition(D).IsMixin) then
  1281. begin
  1282. Old:=FindGlobalDef(D.Name);
  1283. if Old<>nil then
  1284. raise EWebIDLParser.Create('Duplicate identifier '+D.Name+' at '+GetDefPos(D)+' and '+GetDefPos(Old));
  1285. FGlobalDefs.Add(D.Name,D);
  1286. end
  1287. else
  1288. writeln('TBaseWebIDLToPas.AddJSIdentifier SubIdentifier: '+D.Name+' at '+GetDefPos(D)+' Parent=',D.Parent.Name,':',D.Parent.ClassName,' at ',GetDefPos(D.Parent));
  1289. end;
  1290. procedure TBaseWebIDLToPas.ResolveTypeDefs(aList: TIDLDefinitionList);
  1291. var
  1292. D: TIDLDefinition;
  1293. begin
  1294. For D in aList do
  1295. ResolveTypeDef(D);
  1296. end;
  1297. procedure TBaseWebIDLToPas.ResolveTypeDef(D: TIDLDefinition);
  1298. procedure ResolveTypeName(const aTypeName: string);
  1299. var
  1300. Def: TIDLDefinition;
  1301. Data: TPasData;
  1302. begin
  1303. Def:=FindGlobalDef(aTypeName);
  1304. if Def=nil then
  1305. begin
  1306. if NameToWebIDLBaseType(aTypeName)=wibtNone then
  1307. writeln('Type ',aTypeName,' not found at ',GetDefPos(D));
  1308. end
  1309. else
  1310. begin
  1311. Data:=TPasData(D.Data);
  1312. if Data=nil then
  1313. Data:=CreatePasName('',D);
  1314. Data.Resolved:=Def;
  1315. end;
  1316. end;
  1317. var
  1318. DMD: TIDLDictionaryMemberDefinition;
  1319. IT: TIDLIterableDefinition;
  1320. SerializerD: TIDLSerializerDefinition;
  1321. begin
  1322. if D=nil then exit;
  1323. //writeln('TBaseWebIDLToPas.ResolveTypeDef START ',D.Name,':',D.ClassName,' at ',GetDefPos(D));
  1324. if D Is TIDLInterfaceDefinition then
  1325. ResolveTypeDefs((D as TIDLInterfaceDefinition).Members)
  1326. else if D Is TIDLDictionaryDefinition then
  1327. ResolveTypeDefs((D as TIDLDictionaryDefinition).Members)
  1328. else if D is TIDLIncludesDefinition then
  1329. else if D Is TIDLFunctionDefinition then
  1330. ResolveTypeDefs((D as TIDLFunctionDefinition).Arguments)
  1331. else if D is TIDLAttributeDefinition then
  1332. ResolveTypeDef(TIDLAttributeDefinition(D).AttributeType)
  1333. else if D is TIDLArgumentDefinition then
  1334. ResolveTypeDef(TIDLArgumentDefinition(D).ArgumentType)
  1335. else if D is TIDLTypeDefDefinition then
  1336. ResolveTypeName(TIDLTypeDefDefinition(D).TypeName)
  1337. else if D is TIDLConstDefinition then
  1338. ResolveTypeName(TIDLConstDefinition(D).TypeName)
  1339. else if D is TIDLSerializerDefinition then
  1340. begin
  1341. SerializerD:=TIDLSerializerDefinition(D);
  1342. ResolveTypeDef(SerializerD.SerializerFunction);
  1343. end
  1344. else if D is TIDLDictionaryMemberDefinition then
  1345. begin
  1346. DMD:=TIDLDictionaryMemberDefinition(D);
  1347. ResolveTypeDef(DMD.MemberType);
  1348. ResolveTypeDef(DMD.DefaultValue);
  1349. end
  1350. else if D is TIDLEnumDefinition then
  1351. else if D is TIDLSetlikeDefinition then
  1352. ResolveTypeDef(TIDLSetlikeDefinition(D).ElementType)
  1353. else if D is TIDLImplementsOrIncludesDefinition then
  1354. else if D is TIDLIterableDefinition then
  1355. begin
  1356. IT:=TIDLIterableDefinition(D);
  1357. ResolveTypeDef(IT.ValueType);
  1358. ResolveTypeDef(IT.KeyType);
  1359. end
  1360. else {if Verbose then}
  1361. writeln('TBaseWebIDLToPas.ResolveTypeDef unknown ',D.Name,':',D.ClassName,' at ',GetDefPos(D));
  1362. end;
  1363. function TBaseWebIDLToPas.FindGlobalDef(const aName: UTF8String
  1364. ): TIDLDefinition;
  1365. begin
  1366. Result:=TIDLDefinition(FGlobalDefs.Find(aName));
  1367. end;
  1368. function TBaseWebIDLToPas.GetDefPos(Def: TIDLBaseObject; WithoutFile: boolean
  1369. ): string;
  1370. begin
  1371. Result:='('+IntToStr(Def.Line)+','+IntToStr(Def.Column)+')';
  1372. if not WithoutFile then
  1373. Result:=Def.SrcFile+Result;
  1374. end;
  1375. function TBaseWebIDLToPas.GetPasDataPos(D: TPasData; WithoutFile: boolean
  1376. ): string;
  1377. begin
  1378. Result:='('+IntToStr(D.Line)+','+IntToStr(D.Column)+')';
  1379. if not WithoutFile then
  1380. Result:=D.SrcFile+Result;
  1381. end;
  1382. procedure TBaseWebIDLToPas.SetTypeAliases(AValue: TStrings);
  1383. begin
  1384. if FTypeAliases=AValue then Exit;
  1385. FTypeAliases.Assign(AValue);
  1386. end;
  1387. procedure TBaseWebIDLToPas.SetIncludeInterfaceCode(AValue: TStrings);
  1388. begin
  1389. if FIncludeInterfaceCode=AValue then Exit;
  1390. FIncludeInterfaceCode.Assign(AValue);
  1391. end;
  1392. procedure TBaseWebIDLToPas.SetIncludeImplementationCode(AValue: TStrings);
  1393. begin
  1394. if FIncludeImplementationCode=AValue then Exit;
  1395. FIncludeImplementationCode.Assign(AValue);
  1396. end;
  1397. procedure TBaseWebIDLToPas.AllocatePasNames(aList: TIDLDefinitionList; ParentName: String = '');
  1398. var
  1399. D: TIDLDefinition;
  1400. begin
  1401. For D in aList do
  1402. AllocatePasName(D,ParentName);
  1403. end;
  1404. procedure TBaseWebIDLToPas.ProcessDefinitions;
  1405. begin
  1406. FContext.AppendPartials;
  1407. FContext.AppendIncludes;
  1408. AllocatePasNames(FContext.Definitions);
  1409. ResolveTypeDefs(FContext.Definitions);
  1410. end;
  1411. procedure TBaseWebIDLToPas.Execute;
  1412. begin
  1413. if Verbose then
  1414. begin
  1415. WriteOptions;
  1416. DoLog('');
  1417. end;
  1418. FContext:=CreateContext;
  1419. try
  1420. FContext.Aliases:=Self.TypeAliases;
  1421. Parse;
  1422. if Verbose then
  1423. DoLog('Parsed %d definitions.',[Context.Definitions.Count]);
  1424. ProcessDefinitions;
  1425. if Verbose then
  1426. DoLog('Processed %d definitions.',[Context.Definitions.Count]);
  1427. WritePascal;
  1428. finally
  1429. FreeAndNil(FContext);
  1430. end;
  1431. end;
  1432. procedure TBaseWebIDLToPas.WriteOptions;
  1433. var
  1434. i: Integer;
  1435. L: TStringList;
  1436. begin
  1437. L:=TStringList.Create;
  1438. try
  1439. GetOptions(L,true);
  1440. for i:=0 to L.Count-1 do
  1441. DoLog(L[i]);
  1442. finally
  1443. L.Free;
  1444. end;
  1445. end;
  1446. end.