webidltopas2js.pp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  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 webidltopas2js;
  12. {$mode ObjFPC}{$H+}
  13. interface
  14. uses
  15. Classes, SysUtils, webidldefs, webidltopas, Contnrs;
  16. type
  17. TPas2jsConversionOption = (
  18. p2jcoUseNativeTypeAliases,
  19. p2jcoExternalConst
  20. );
  21. TPas2jsConversionOptions = Set of TPas2jsConversionOption;
  22. const
  23. Pas2jsConversionOptionNames: array[TPas2jsConversionOption] of string = (
  24. 'UseNativeTypeAliases',
  25. 'ExternalConst'
  26. );
  27. type
  28. { TWebIDLToPas2js }
  29. TWebIDLToPas2js = class(TBaseWebIDLToPas)
  30. Private
  31. FPas2jsOptions: TPas2jsConversionOptions;
  32. Protected
  33. Function BaseUnits: String; override;
  34. // Auxiliary routines
  35. procedure GetOptions(L: TStrings; Full: boolean); override;
  36. function GetTypeName(const aTypeName: String; ForTypeDef: Boolean=False
  37. ): String; override;
  38. function GetInterfaceDefHead(Intf: TIDLInterfaceDefinition): String;
  39. override;
  40. // Code generation routines. Return the number of actually written defs.
  41. function WriteFunctionDefinition(aParent: TIDLInterfaceDefinition; aDef: TIDLFunctionDefinition): Boolean;
  42. override;
  43. function WritePrivateReadOnlyFields(aParent: TIDLDefinition; aList: TIDLDefinitionList): Integer;
  44. override;
  45. function WriteProperties(aParent: TIDLDefinition; aList: TIDLDefinitionList): Integer; override;
  46. // Definitions. Return true if a definition was written.
  47. function WriteConst(aConst: TIDLConstDefinition): Boolean; override;
  48. function WriteField(aAttr: TIDLAttributeDefinition): Boolean; override;
  49. function WritePrivateReadOnlyField(aAttr: TIDLAttributeDefinition): Boolean; virtual;
  50. function WriteReadonlyProperty(aParent: TIDLDefinition; aAttr: TIDLAttributeDefinition): Boolean; virtual;
  51. Public
  52. constructor Create(TheOwner: TComponent); override;
  53. Property Pas2jsOptions: TPas2jsConversionOptions Read FPas2jsOptions Write FPas2jsOptions;
  54. Published
  55. Property BaseOptions;
  56. Property ClassPrefix;
  57. Property ClassSuffix;
  58. Property DictionaryClassParent;
  59. Property FieldPrefix;
  60. Property IncludeImplementationCode;
  61. Property IncludeInterfaceCode;
  62. Property InputFileName;
  63. Property OutputFileName;
  64. Property TypeAliases;
  65. Property Verbose;
  66. Property WebIDLVersion;
  67. end;
  68. function Pas2jsConversionOptionsToStr(Opts: TPas2jsConversionOptions): string;
  69. implementation
  70. function Pas2jsConversionOptionsToStr(Opts: TPas2jsConversionOptions): string;
  71. var
  72. o: TPas2jsConversionOption;
  73. begin
  74. Result:='';
  75. for o in Opts do
  76. begin
  77. if Result<>'' then Result:=Result+',';
  78. Result:=Result+Pas2jsConversionOptionNames[o];
  79. end;
  80. Result:='['+Result+']';
  81. end;
  82. { TWebIDLToPas2js }
  83. function TWebIDLToPas2js.BaseUnits: String;
  84. begin
  85. Result:='SysUtils, JS';
  86. end;
  87. procedure TWebIDLToPas2js.GetOptions(L: TStrings; Full: boolean);
  88. begin
  89. inherited GetOptions(L, Full);
  90. L.Add('Extended Options: '+Pas2jsConversionOptionsToStr(Pas2jsOptions));
  91. end;
  92. function TWebIDLToPas2js.GetTypeName(const aTypeName: String;
  93. ForTypeDef: Boolean): String;
  94. Function UsePascalType(Const aPascalType: string): String;
  95. begin
  96. if (p2jcoUseNativeTypeAliases in Pas2jsOptions) and ForTypeDef then
  97. Result:=StringReplace(aTypeName,' ','',[rfReplaceAll])
  98. else
  99. Result:=aPascalType;
  100. end;
  101. begin
  102. Case aTypeName of
  103. 'union': Result:='JSValue';
  104. 'short': Result:=UsePascalType('Integer');
  105. 'long': Result:=UsePascalType('Integer');
  106. 'long long': Result:=UsePascalType('NativeInt');
  107. 'unsigned short': Result:=UsePascalType('Cardinal');
  108. 'unrestricted float': Result:=UsePascalType('Double');
  109. 'unrestricted double': Result:=UsePascalType('Double');
  110. 'unsigned long': Result:=UsePascalType('NativeInt');
  111. 'unsigned long long': Result:=UsePascalType('NativeInt');
  112. 'octet': Result:=UsePascalType('Byte');
  113. 'any': Result:=UsePascalType('JSValue');
  114. 'float': Result:=UsePascalType('Double');
  115. 'double': Result:=UsePascalType('Double');
  116. 'DOMString',
  117. 'USVString',
  118. 'ByteString': Result:=UsePascalType('String');
  119. else
  120. Result:=inherited GetTypeName(aTypeName,ForTypeDef);
  121. end;
  122. end;
  123. function TWebIDLToPas2js.GetInterfaceDefHead(Intf: TIDLInterfaceDefinition
  124. ): String;
  125. var
  126. aParentName: String;
  127. begin
  128. Result:='class external name '+MakePascalString(Intf.Name,True);
  129. if Assigned(Intf.ParentInterface) then
  130. aParentName:=GetName(Intf.ParentInterface)
  131. else
  132. aParentName:=GetTypeName(Intf.ParentName);
  133. if aParentName<>'' then
  134. Result:=Result+' ('+aParentName+')';
  135. end;
  136. function TWebIDLToPas2js.WriteFunctionDefinition(
  137. aParent: TIDLInterfaceDefinition; aDef: TIDLFunctionDefinition): Boolean;
  138. Var
  139. FN,RT,Suff,Args: String;
  140. Overloads: TFPObjectList;
  141. I: Integer;
  142. begin
  143. Result:=True;
  144. if aParent=nil then ;
  145. Suff:='';
  146. RT:='';
  147. if not (foConstructor in aDef.Options) then
  148. begin
  149. FN:=GetName(aDef);
  150. if FN<>aDef.Name then
  151. Suff:=Format('; external name ''%s''',[aDef.Name]);
  152. RT:=GetTypeName(aDef.ReturnType,False);
  153. if (RT='void') then
  154. RT:='';
  155. end
  156. else
  157. FN:='New';
  158. Overloads:=GetOverloads(ADef);
  159. try
  160. for I:=0 to aDef.Arguments.Count-1 do
  161. if aDef.Argument[i].HasEllipsis then
  162. Suff:='; varargs';
  163. if Overloads.Count>1 then
  164. Suff:=Suff+'; overload';
  165. For I:=0 to Overloads.Count-1 do
  166. begin
  167. Args:=GetArguments(TIDLDefinitionList(Overloads[i]),False);
  168. if (RT='') then
  169. begin
  170. if not (foConstructor in aDef.Options) then
  171. AddLn('Procedure %s%s%s;',[FN,Args,Suff])
  172. else
  173. AddLn('constructor %s%s%s;',[FN,Args,Suff]);
  174. end
  175. else
  176. AddLn('function %s%s: %s%s;',[FN,Args,RT,Suff])
  177. end;
  178. finally
  179. Overloads.Free;
  180. end;
  181. end;
  182. function TWebIDLToPas2js.WritePrivateReadOnlyFields(aParent: TIDLDefinition;
  183. aList: TIDLDefinitionList): Integer;
  184. Var
  185. D: TIDLDefinition;
  186. A: TIDLAttributeDefinition absolute D;
  187. begin
  188. Result:=0;
  189. if aParent=nil then ;
  190. For D in aList do
  191. if (D is TIDLAttributeDefinition) then
  192. if (aoReadOnly in A.Options) then
  193. if WritePrivateReadOnlyField(A) then
  194. Inc(Result);
  195. end;
  196. function TWebIDLToPas2js.WriteProperties(aParent: TIDLDefinition;
  197. aList: TIDLDefinitionList): Integer;
  198. Var
  199. D: TIDLDefinition;
  200. A: TIDLAttributeDefinition absolute D;
  201. begin
  202. Result:=0;
  203. For D in aList do
  204. if (D is TIDLAttributeDefinition) then
  205. if (aoReadOnly in A.Options) then
  206. if WriteReadOnlyProperty(aParent,A) then
  207. Inc(Result);
  208. end;
  209. function TWebIDLToPas2js.WriteConst(aConst: TIDLConstDefinition): Boolean;
  210. Const
  211. ConstTypes: Array[TConstType] of String =
  212. ('Double','NativeInt','Boolean','JSValue','JSValue','JSValue','JSValue','String','JSValue','JSValue');
  213. Var
  214. S: String;
  215. begin
  216. Result:=True;
  217. // Consts cannot be strings
  218. if p2jcoExternalConst in Pas2jsOptions then
  219. begin
  220. S:=ConstTypes[aConst.ConstType];
  221. Addln('%s: %s;',[GetName(aConst),S])
  222. end
  223. else
  224. Result:=inherited WriteConst(aConst);
  225. end;
  226. function TWebIDLToPas2js.WriteField(aAttr: TIDLAttributeDefinition): Boolean;
  227. Var
  228. Def,TN,N: String;
  229. begin
  230. Result:=True;
  231. N:=GetName(aAttr);
  232. if aAttr.AttributeType=nil then
  233. begin
  234. AddLn('skipping field without type: "'+N+'"');
  235. exit;
  236. end;
  237. TN:=GetTypeName(aAttr.AttributeType);
  238. if TN='record' then
  239. TN:='TJSObject';
  240. if SameText(N,TN) then
  241. N:='_'+N;
  242. Def:=Format('%s: %s;',[N,TN]);
  243. if (N<>aAttr.Name) then
  244. Def:=Def+Format('external name ''%s'';',[aAttr.Name]);
  245. AddLn(Def);
  246. end;
  247. function TWebIDLToPas2js.WritePrivateReadOnlyField(
  248. aAttr: TIDLAttributeDefinition): Boolean;
  249. begin
  250. AddLn('%s%s: %s; external name ''%s''; ',[FieldPrefix,GetName(aAttr),GetTypeName(aAttr.AttributeType),aAttr.Name]);
  251. Result:=true;
  252. end;
  253. function TWebIDLToPas2js.WriteReadonlyProperty(aParent: TIDLDefinition;
  254. aAttr: TIDLAttributeDefinition): Boolean;
  255. Var
  256. TN,N,PN: String;
  257. begin
  258. Result:=True;
  259. if aParent=nil then ;
  260. N:=GetName(aAttr);
  261. PN:=N;
  262. TN:=GetTypeName(aAttr.AttributeType);
  263. if SameText(PN,TN) then
  264. PN:='_'+PN;
  265. AddLn('Property %s: %s Read %s%s; ',[PN,TN,FieldPrefix,N]);
  266. end;
  267. constructor TWebIDLToPas2js.Create(TheOwner: TComponent);
  268. begin
  269. inherited Create(TheOwner);
  270. Switches.Add('modeswitch externalclass');
  271. end;
  272. end.