webidltopas2js.pp 8.8 KB

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