tcgenerics.pp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. unit tcgenerics;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. Classes, SysUtils, fpcunit, pastree, testregistry, pscanner, tctypeparser;
  6. Type
  7. { TTestGenerics }
  8. TTestGenerics = Class(TBaseTestTypeParser)
  9. Published
  10. Procedure TestObjectGenerics;
  11. Procedure TestRecordGenerics;
  12. Procedure TestArrayGenerics;
  13. Procedure TestArrayGenericsDelphi;
  14. Procedure TestProcTypeGenerics;
  15. Procedure TestGenericConstraint;
  16. Procedure TestGenericInterfaceConstraint;
  17. Procedure TestDeclarationConstraint;
  18. Procedure TestSpecializationDelphi;
  19. Procedure TestDeclarationDelphi;
  20. Procedure TestDeclarationDelphiSpecialize;
  21. Procedure TestDeclarationFPC;
  22. Procedure TestMethodImplementation;
  23. Procedure TestInlineSpecializationInArgument;
  24. Procedure TestSpecializeNested;
  25. Procedure TestInlineSpecializeInStatement;
  26. Procedure TestInlineSpecializeInStatementDelphi;
  27. Procedure TestGenericFunction_Program;
  28. Procedure TestGenericFunction_Unit;
  29. end;
  30. implementation
  31. procedure TTestGenerics.TestObjectGenerics;
  32. begin
  33. Add([
  34. 'Type',
  35. 'Generic TSomeClass<T> = Object',
  36. ' b : T;',
  37. 'end;',
  38. '']);
  39. ParseDeclarations;
  40. end;
  41. procedure TTestGenerics.TestRecordGenerics;
  42. begin
  43. Add([
  44. 'Type',
  45. ' Generic TSome<T> = Record',
  46. ' b : T;',
  47. ' end;',
  48. '']);
  49. ParseDeclarations;
  50. end;
  51. procedure TTestGenerics.TestArrayGenerics;
  52. begin
  53. Add([
  54. 'Type',
  55. ' Generic TSome<T> = array of T;',
  56. ' Generic TStatic<R,T> = array[R] of T;',
  57. '']);
  58. ParseDeclarations;
  59. end;
  60. procedure TTestGenerics.TestArrayGenericsDelphi;
  61. begin
  62. Add([
  63. '{$mode delphi}',
  64. 'Type',
  65. ' TSome<T> = array of T;',
  66. ' TStatic<R,T> = array[R] of T;',
  67. '']);
  68. ParseDeclarations;
  69. end;
  70. procedure TTestGenerics.TestProcTypeGenerics;
  71. begin
  72. Add([
  73. 'Type',
  74. ' Generic TSome<T> = procedure(v: T);',
  75. ' Generic TFunc<R,T> = function(b: R): T;',
  76. '']);
  77. ParseDeclarations;
  78. end;
  79. procedure TTestGenerics.TestGenericConstraint;
  80. begin
  81. Add([
  82. 'Type',
  83. 'Generic TSomeClass<T: TObject> = class',
  84. ' b : T;',
  85. 'end;',
  86. 'Generic TBird<T: class> = class',
  87. ' c : TBird<T>;',
  88. 'end;',
  89. 'Generic TEagle<T: record> = class',
  90. 'end;',
  91. 'Generic TEagle<T: constructor> = class',
  92. 'end;',
  93. '']);
  94. ParseDeclarations;
  95. end;
  96. procedure TTestGenerics.TestGenericInterfaceConstraint;
  97. begin
  98. Add([
  99. 'Type',
  100. 'TIntfA = interface end;',
  101. 'TIntfB = interface end;',
  102. 'TBird = class(TInterfacedObject,TIntfA,TIntfB) end;',
  103. 'Generic TAnt<T: TIntfA, TIntfB> = class',
  104. ' b: T;',
  105. ' c: TAnt<T>;',
  106. 'end;',
  107. 'Generic TFly<T: TIntfA, TIntfB; S> = class',
  108. ' b: S;',
  109. ' c: TFly<T>;',
  110. 'end;',
  111. '']);
  112. ParseDeclarations;
  113. end;
  114. procedure TTestGenerics.TestDeclarationConstraint;
  115. Var
  116. T : TPasClassType;
  117. begin
  118. Scanner.CurrentModeSwitches:=[msDelphi]+Scanner.CurrentModeSwitches ;
  119. Source.Add('Type');
  120. Source.Add(' TSomeClass<T: T2> = Class(TObject)');
  121. Source.Add(' b : T;');
  122. Source.Add(' end;');
  123. ParseDeclarations;
  124. AssertNotNull('have generic definition',Declarations.Classes);
  125. AssertEquals('have generic definition',1,Declarations.Classes.Count);
  126. AssertEquals('Pascal class',TPasClassType,TObject(Declarations.Classes[0]).ClassType);
  127. T:=TPasClassType(Declarations.Classes[0]);
  128. AssertNotNull('have generic templates',T.GenericTemplateTypes);
  129. AssertEquals('1 template types',1,T.GenericTemplateTypes.Count);
  130. AssertSame('Parent 0 is class',T,TPasElement(T.GenericTemplateTypes[0]).Parent);
  131. AssertEquals('Type constraint is recorded','T2',TPasGenericTemplateType(T.GenericTemplateTypes[0]).TypeConstraint);
  132. end;
  133. procedure TTestGenerics.TestSpecializationDelphi;
  134. begin
  135. ParseType('TFPGList<integer>',TPasSpecializeType,'');
  136. end;
  137. procedure TTestGenerics.TestDeclarationDelphi;
  138. Var
  139. T : TPasClassType;
  140. begin
  141. Scanner.CurrentModeSwitches:=[msDelphi]+Scanner.CurrentModeSwitches ;
  142. Source.Add('Type');
  143. Source.Add(' TSomeClass<T,T2> = Class(TObject)');
  144. Source.Add(' b : T;');
  145. Source.Add(' b2 : T2;');
  146. Source.Add(' end;');
  147. ParseDeclarations;
  148. AssertNotNull('have generic definition',Declarations.Classes);
  149. AssertEquals('have generic definition',1,Declarations.Classes.Count);
  150. AssertEquals('Pascal class',TPasClassType,TObject(Declarations.Classes[0]).ClassType);
  151. T:=TPasClassType(Declarations.Classes[0]);
  152. AssertNotNull('have generic templates',T.GenericTemplateTypes);
  153. AssertEquals('2 template types',2,T.GenericTemplateTypes.Count);
  154. AssertSame('Parent 0 is class',T,TPasElement(T.GenericTemplateTypes[0]).Parent);
  155. AssertSame('Parent 1 is class',T,TPasElement(T.GenericTemplateTypes[1]).Parent);
  156. end;
  157. procedure TTestGenerics.TestDeclarationDelphiSpecialize;
  158. Var
  159. T : TPasClassType;
  160. begin
  161. Scanner.CurrentModeSwitches:=[msDelphi]+Scanner.CurrentModeSwitches ;
  162. Source.Add('Type');
  163. Source.Add(' TSomeClass<T,T2> = Class(TSomeGeneric<Integer,Integer>)');
  164. Source.Add(' b : T;');
  165. Source.Add(' b2 : T2;');
  166. Source.Add(' end;');
  167. ParseDeclarations;
  168. AssertNotNull('have generic definition',Declarations.Classes);
  169. AssertEquals('have generic definition',1,Declarations.Classes.Count);
  170. AssertEquals('Pascal class',TPasClassType,TObject(Declarations.Classes[0]).ClassType);
  171. T:=TPasClassType(Declarations.Classes[0]);
  172. AssertEquals('Name is correct','TSomeClass',T.Name);
  173. AssertNotNull('have generic templates',T.GenericTemplateTypes);
  174. AssertEquals('2 template types',2,T.GenericTemplateTypes.Count);
  175. AssertSame('Parent 0 is class',T,TPasElement(T.GenericTemplateTypes[0]).Parent);
  176. AssertSame('Parent 1 is class',T,TPasElement(T.GenericTemplateTypes[1]).Parent);
  177. end;
  178. procedure TTestGenerics.TestDeclarationFPC;
  179. Var
  180. T : TPasClassType;
  181. begin
  182. Scanner.CurrentModeSwitches:=[msDelphi]+Scanner.CurrentModeSwitches;
  183. Source.Add('Type');
  184. Source.Add(' TSomeClass<T;T2> = Class(TObject)');
  185. Source.Add(' b : T;');
  186. Source.Add(' b2 : T2;');
  187. Source.Add(' end;');
  188. ParseDeclarations;
  189. AssertNotNull('have generic definition',Declarations.Classes);
  190. AssertEquals('have generic definition',1,Declarations.Classes.Count);
  191. AssertEquals('Pascal class',TPasClassType,TObject(Declarations.Classes[0]).ClassType);
  192. T:=TPasClassType(Declarations.Classes[0]);
  193. AssertNotNull('have generic templates',T.GenericTemplateTypes);
  194. AssertEquals('2 template types',2,T.GenericTemplateTypes.Count);
  195. AssertSame('Parent 0 is class',T,TPasElement(T.GenericTemplateTypes[0]).Parent);
  196. AssertSame('Parent 1 is class',T,TPasElement(T.GenericTemplateTypes[1]).Parent);
  197. end;
  198. procedure TTestGenerics.TestMethodImplementation;
  199. begin
  200. With source do
  201. begin
  202. Add('unit afile;');
  203. Add('{$MODE DELPHI}');
  204. Add('interface');
  205. Add('type');
  206. Add(' TTest<T> = object');
  207. Add(' procedure foo(v:T);');
  208. Add(' procedure bar<Y>(v:T);');
  209. Add(' type');
  210. Add(' TSub = class');
  211. Add(' procedure DoIt<Y>(v:T);');
  212. Add(' end;');
  213. Add(' end;');
  214. Add('implementation');
  215. Add('procedure TTest<T>.foo;');
  216. Add('begin');
  217. Add('end;');
  218. Add('procedure TTest<T>.bar<Y>;');
  219. Add('begin');
  220. Add('end;');
  221. Add('procedure TTest<T>.TSub.DoIt<Y>;');
  222. Add('begin');
  223. Add('end;');
  224. end;
  225. ParseModule;
  226. end;
  227. procedure TTestGenerics.TestInlineSpecializationInArgument;
  228. begin
  229. With source do
  230. begin
  231. Add('unit afile;');
  232. Add('{$MODE DELPHI}');
  233. Add('interface');
  234. Add('type');
  235. Add(' TFoo=class');
  236. Add(' procedure foo(var Node:TSomeGeneric<TBoundingBox>;const index:Integer);');
  237. Add(' end;');
  238. Add('implementation');
  239. end;
  240. ParseModule;
  241. end;
  242. procedure TTestGenerics.TestSpecializeNested;
  243. begin
  244. Add([
  245. 'Type',
  246. ' generic TSomeClass<A,B> = class(specialize TOther<A,specialize TAnother<B>>) end;',
  247. '']);
  248. ParseDeclarations;
  249. end;
  250. procedure TTestGenerics.TestInlineSpecializeInStatement;
  251. begin
  252. Add([
  253. 'begin',
  254. ' t:=specialize a<b>;',
  255. ' t:=a.specialize b<c>;',
  256. '']);
  257. ParseModule;
  258. end;
  259. procedure TTestGenerics.TestInlineSpecializeInStatementDelphi;
  260. begin
  261. Add([
  262. 'begin',
  263. ' vec:=TVector<double>.create;',
  264. ' b:=a<b;',
  265. ' t:=a<b.c<d,e.f>>;',
  266. ' t:=a.b<c>;',
  267. ' t:=a<b>.c;',
  268. // forbidden:' t:=a<b<c>.d>;',
  269. '']);
  270. ParseModule;
  271. end;
  272. procedure TTestGenerics.TestGenericFunction_Program;
  273. begin
  274. Add([
  275. 'generic function IfThen<T>(val:boolean;const iftrue:T; const iffalse:T) :T; inline; overload;',
  276. 'begin',
  277. 'end;',
  278. 'begin',
  279. ' specialize IfThen<word>(true,2,3);',
  280. '']);
  281. ParseModule;
  282. end;
  283. procedure TTestGenerics.TestGenericFunction_Unit;
  284. begin
  285. Add([
  286. 'unit afile;',
  287. 'interface',
  288. 'generic function Get<T>(val: T) :T;',
  289. 'implementation',
  290. 'generic function Get<T>(val: T) :T;',
  291. 'begin',
  292. 'end;',
  293. 'initialization',
  294. ' specialize GetIt<word>(2);',
  295. '']);
  296. ParseModule;
  297. end;
  298. initialization
  299. RegisterTest(TTestGenerics);
  300. end.