unit TCGenerics; {$mode objfpc}{$H+} interface uses Classes, SysUtils, fpcunit, testregistry, TCModules, FPPas2Js; type { TTestGenerics } TTestGenerics = class(TCustomTestModule) Published // generic record Procedure TestGen_RecordEmpty; Procedure TestGen_Record_ClassProc_ObjFPC; //Procedure TestGen_Record_ClassProc_Delphi; //Procedure TestGen_Record_ReferGenClass_DelphiFail; // generic class Procedure TestGen_ClassEmpty; Procedure TestGen_Class_EmptyMethod; Procedure TestGen_Class_TList; Procedure TestGen_Class_TCustomList; Procedure TestGen_ClassAncestor; Procedure TestGen_Class_TypeInfo; Procedure TestGen_Class_TypeOverload; // ToDo TBird, TBird, TBird Procedure TestGen_Class_ClassProperty; Procedure TestGen_Class_ClassProc_ObjFPC; //Procedure TestGen_Class_ClassProc_Delphi; //Procedure TestGen_Class_ReferGenClass_DelphiFail; Procedure TestGen_Class_ClassConstructor; // ToDo: rename local const T // generic external class procedure TestGen_ExtClass_Array; // statements Procedure TestGen_InlineSpec_Constructor; Procedure TestGen_CallUnitImplProc; Procedure TestGen_IntAssignTemplVar; Procedure TestGen_TypeCastDotField; // generic helper procedure TestGen_HelperForArray; // generic functions procedure TestGenProc_Function_ObjFPC; procedure TestGenProc_Function_Delphi; procedure TestGenProc_Overload; procedure TestGenProc_Forward; procedure TestGenProc_Infer_OverloadForward; procedure TestGenProc_TypeInfo; procedure TestGenProc_Infer_Widen; procedure TestGenProc_Infer_PassAsArg; // ToDo: FuncName:= // generic methods procedure TestGenMethod_ObjFPC; end; implementation { TTestGenerics } procedure TTestGenerics.TestGen_RecordEmpty; begin StartProgram(false); Add([ 'type', ' generic TRecA = record', ' end;', 'var a,b: specialize TRecA;', 'begin', ' if a=b then ;']); ConvertProgram; CheckSource('TestGen_RecordEmpty', LinesToStr([ // statements 'rtl.recNewT($mod, "TRecA$G1", function () {', ' this.$eq = function (b) {', ' return true;', ' };', ' this.$assign = function (s) {', ' return this;', ' };', '});', 'this.a = $mod.TRecA$G1.$new();', 'this.b = $mod.TRecA$G1.$new();', '']), LinesToStr([ // $mod.$main 'if ($mod.a.$eq($mod.b)) ;' ])); end; procedure TTestGenerics.TestGen_Record_ClassProc_ObjFPC; begin StartProgram(false); Add([ '{$modeswitch AdvancedRecords}', 'type', ' generic TPoint = record', ' class var x: T;', ' class procedure Fly; static;', ' end;', 'class procedure Tpoint.Fly;', 'begin', ' x:=x+3;', ' tpoint.x:=tpoint.x+4;', ' Fly;', ' tpoint.Fly;', 'end;', 'var p: specialize TPoint;', 'begin', ' p.x:=p.x+10;', ' p.Fly;', ' p.Fly();', '']); ConvertProgram; CheckSource('TestGen_Record_ClassProc', LinesToStr([ // statements 'rtl.recNewT($mod, "TPoint$G1", function () {', ' this.x = 0;', ' this.$eq = function (b) {', ' return true;', ' };', ' this.$assign = function (s) {', ' return this;', ' };', ' this.Fly = function () {', ' $mod.TPoint$G1.x = $mod.TPoint$G1.x + 3;', ' $mod.TPoint$G1.x = $mod.TPoint$G1.x + 4;', ' $mod.TPoint$G1.Fly();', ' $mod.TPoint$G1.Fly();', ' };', '}, true);', 'this.p = $mod.TPoint$G1.$new();', '']), LinesToStr([ // $mod.$main '$mod.TPoint$G1.x = $mod.p.x + 10;', '$mod.p.Fly();', '$mod.p.Fly();', ''])); end; procedure TTestGenerics.TestGen_ClassEmpty; begin StartProgram(false); Add([ 'type', ' TObject = class end;', ' generic TBird = class', ' end;', 'var a,b: specialize TBird;', 'begin', ' if a=b then ;']); ConvertProgram; CheckSource('TestGen_ClassEmpty', LinesToStr([ // statements 'rtl.createClass($mod, "TObject", null, function () {', ' this.$init = function () {', ' };', ' this.$final = function () {', ' };', '});', 'rtl.createClass($mod, "TBird$G1", $mod.TObject, function () {', '});', 'this.a = null;', 'this.b = null;', '']), LinesToStr([ // $mod.$main 'if ($mod.a === $mod.b) ;' ])); end; procedure TTestGenerics.TestGen_Class_EmptyMethod; begin StartProgram(false); Add([ 'type', ' TObject = class end;', ' generic TBird = class', ' function Fly(w: T): T;', ' end;', 'function TBird.Fly(w: T): T;', 'begin', 'end;', 'var a: specialize TBird;', 'begin', ' if a.Fly(3)=4 then ;']); ConvertProgram; CheckSource('TestGen_Class_EmptyMethod', LinesToStr([ // statements 'rtl.createClass($mod, "TObject", null, function () {', ' this.$init = function () {', ' };', ' this.$final = function () {', ' };', '});', 'rtl.createClass($mod, "TBird$G1", $mod.TObject, function () {', ' this.Fly = function (w) {', ' var Result = 0;', ' return Result;', ' };', '});', 'this.a = null;', '']), LinesToStr([ // $mod.$main ' if ($mod.a.Fly(3) === 4) ;' ])); end; procedure TTestGenerics.TestGen_Class_TList; begin StartProgram(false); Add([ '{$mode objfpc}', 'type', ' TObject = class end;', ' generic TList = class', ' strict private', ' FItems: array of T;', ' function GetItems(Index: longint): T;', ' procedure SetItems(Index: longint; Value: T);', ' public', ' procedure Alter(w: T);', ' property Items[Index: longint]: T read GetItems write SetItems; default;', ' end;', ' TWordList = specialize TList;', 'function TList.GetItems(Index: longint): T;', 'begin', ' Result:=FItems[Index];', 'end;', 'procedure TList.SetItems(Index: longint; Value: T);', 'begin', ' FItems[Index]:=Value;', 'end;', 'procedure TList.Alter(w: T);', 'begin', ' SetLength(FItems,length(FItems)+1);', ' Insert(w,FItems,2);', ' Delete(FItems,2,3);', 'end;', 'var l: TWordList;', ' w: word;', 'begin', ' l[1]:=w;', ' w:=l[2];', '']); ConvertProgram; CheckSource('TestGen_Class_TList', LinesToStr([ // statements 'rtl.createClass($mod, "TObject", null, function () {', ' this.$init = function () {', ' };', ' this.$final = function () {', ' };', '});', 'rtl.createClass($mod, "TList$G1", $mod.TObject, function () {', ' this.$init = function () {', ' $mod.TObject.$init.call(this);', ' this.FItems = [];', ' };', ' this.$final = function () {', ' this.FItems = undefined;', ' $mod.TObject.$final.call(this);', ' };', ' this.GetItems = function (Index) {', ' var Result = 0;', ' Result = this.FItems[Index];', ' return Result;', ' };', ' this.SetItems = function (Index, Value) {', ' this.FItems[Index] = Value;', ' };', ' this.Alter = function (w) {', ' this.FItems = rtl.arraySetLength(this.FItems, 0, rtl.length(this.FItems) + 1);', ' this.FItems.splice(2, 0, w);', ' this.FItems.splice(2, 3);', ' };', '});', 'this.l = null;', 'this.w = 0;', '']), LinesToStr([ // $mod.$main '$mod.l.SetItems(1, $mod.w);', '$mod.w = $mod.l.GetItems(2);', ''])); end; procedure TTestGenerics.TestGen_Class_TCustomList; begin StartProgram(false); Add([ '{$mode delphi}', 'type', ' TObject = class end;', ' TCustomList = class', ' public', ' function PrepareAddingItem: word; virtual;', ' end;', ' TList = class(TCustomList)', ' public', ' function Add: word;', ' end;', ' TWordList = TList;', 'function TCustomList.PrepareAddingItem: word;', 'begin', 'end;', 'function TList.Add: word;', 'begin', ' Result:=PrepareAddingItem;', //' Result:=Self.PrepareAddingItem;', //' with Self do Result:=PrepareAddingItem;', 'end;', 'var l: TWordList;', 'begin', '']); ConvertProgram; CheckSource('TestGen_Class_TCustomList', LinesToStr([ // statements 'rtl.createClass($mod, "TObject", null, function () {', ' this.$init = function () {', ' };', ' this.$final = function () {', ' };', '});', 'rtl.createClass($mod, "TCustomList$G2", $mod.TObject, function () {', ' this.PrepareAddingItem = function () {', ' var Result = 0;', ' return Result;', ' };', '});', 'rtl.createClass($mod, "TList$G1", $mod.TCustomList$G2, function () {', ' this.Add = function () {', ' var Result = 0;', ' Result = this.PrepareAddingItem();', ' return Result;', ' };', '});', 'this.l = null;', '']), LinesToStr([ // $mod.$main ''])); end; procedure TTestGenerics.TestGen_ClassAncestor; begin StartProgram(false); Add([ 'type', ' TObject = class end;', ' generic TBird = class', ' end;', ' generic TEagle = class(specialize TBird)', ' end;', 'var a: specialize TEagle;', 'begin', '']); ConvertProgram; CheckSource('TestGen_ClassAncestor', LinesToStr([ // statements 'rtl.createClass($mod, "TObject", null, function () {', ' this.$init = function () {', ' };', ' this.$final = function () {', ' };', '});', 'rtl.createClass($mod, "TBird$G2", $mod.TObject, function () {', '});', 'rtl.createClass($mod, "TEagle$G1", $mod.TBird$G2, function () {', '});', 'this.a = null;', '']), LinesToStr([ // $mod.$main ''])); end; procedure TTestGenerics.TestGen_Class_TypeInfo; begin Converter.Options:=Converter.Options-[coNoTypeInfo]; StartProgram(false); Add([ 'type', ' TObject = class end;', ' generic TBird = class', ' published', ' m: T;', ' end;', ' TEagle = specialize TBird;', 'var', ' b: specialize TBird;', ' p: pointer;', 'begin', ' p:=typeinfo(TEagle);', ' p:=typeinfo(b);', '']); ConvertProgram; CheckSource('TestGen_TypeInfo', LinesToStr([ // statements 'rtl.createClass($mod, "TObject", null, function () {', ' this.$init = function () {', ' };', ' this.$final = function () {', ' };', '});', 'rtl.createClass($mod, "TBird$G1", $mod.TObject, function () {', ' this.$init = function () {', ' $mod.TObject.$init.call(this);', ' this.m = 0;', ' };', ' var $r = this.$rtti;', ' $r.addField("m", rtl.word);', '});', 'this.b = null;', 'this.p = null;', '']), LinesToStr([ // $mod.$main '$mod.p = $mod.$rtti["TBird$G1"];', '$mod.p = $mod.b.$rtti;', ''])); end; procedure TTestGenerics.TestGen_Class_TypeOverload; begin exit;// ToDo StartProgram(false); Add([ '{$mode delphi}', 'type', ' TObject = class end;', ' TBird = word;', ' TBird = class', ' m: T;', ' end;', ' TEagle = TBird;', 'var', ' b: TBird;', ' e: TEagle;', 'begin', '']); ConvertProgram; CheckSource('TestGen_Class_TypeOverload', LinesToStr([ // statements 'rtl.createClass($mod, "TObject", null, function () {', ' this.$init = function () {', ' };', ' this.$final = function () {', ' };', '});', '']), LinesToStr([ // $mod.$main ''])); end; procedure TTestGenerics.TestGen_Class_ClassProperty; begin StartProgram(false); Add([ '{$mode delphi}', 'type', ' TObject = class end;', ' TBird = class', ' private', ' class var fSize: T;', ' public', ' class property Size: T read fSize write fSize;', ' end;', ' TEagle = TBird;', 'begin', ' TBird.Size:=3+TBird.Size;', '']); ConvertProgram; CheckSource('TestGen_Class_ClassProperty', LinesToStr([ // statements 'rtl.createClass($mod, "TObject", null, function () {', ' this.$init = function () {', ' };', ' this.$final = function () {', ' };', '});', 'rtl.createClass($mod, "TBird$G1", $mod.TObject, function () {', ' this.fSize = 0;', '});', '']), LinesToStr([ // $mod.$main '$mod.TBird$G1.fSize = 3 + $mod.TBird$G1.fSize;', ''])); end; procedure TTestGenerics.TestGen_Class_ClassProc_ObjFPC; begin StartProgram(false); Add([ 'type', ' TObject = class end;', ' generic TPoint = class', ' class var x: T;', ' class procedure Fly; static;', ' class procedure Run;', ' end;', 'class procedure Tpoint.Fly;', 'begin', ' x:=x+3;', ' tpoint.x:=tpoint.x+4;', ' Fly;', ' tpoint.Fly;', ' Run;', ' tpoint.Run;', 'end;', 'class procedure TPoint.Run;', 'begin', ' x:=x+5;', ' tpoint.x:=tpoint.x+6;', ' Fly;', ' tpoint.Fly;', ' Run;', ' tpoint.Run;', 'end;', 'var p: specialize TPoint;', 'begin', '']); ConvertProgram; CheckSource('TestGen_Class_ClassProc', LinesToStr([ // statements 'rtl.createClass($mod, "TObject", null, function () {', ' this.$init = function () {', ' };', ' this.$final = function () {', ' };', '});', 'rtl.createClass($mod, "TPoint$G1", $mod.TObject, function () {', ' this.x = 0;', ' this.Fly = function () {', ' $mod.TPoint$G1.x = $mod.TPoint$G1.x + 3;', ' $mod.TPoint$G1.x = $mod.TPoint$G1.x + 4;', ' $mod.TPoint$G1.Fly();', ' $mod.TPoint$G1.Fly();', ' $mod.TPoint$G1.Run();', ' $mod.TPoint$G1.Run();', ' };', ' this.Run = function () {', ' $mod.TPoint$G1.x = this.x + 5;', ' $mod.TPoint$G1.x = $mod.TPoint$G1.x + 6;', ' this.Fly();', ' $mod.TPoint$G1.Fly();', ' this.Run();', ' $mod.TPoint$G1.Run();', ' };', '});', 'this.p = null;', '']), LinesToStr([ // $mod.$main ''])); end; procedure TTestGenerics.TestGen_Class_ClassConstructor; begin StartProgram(false); Add([ 'type', ' TObject = class end;', ' generic TPoint = class', ' class var x: T;', ' class procedure Fly; static;', ' class constructor Init;', ' end;', 'var count: word;', 'class procedure Tpoint.Fly;', 'begin', 'end;', 'class constructor tpoint.init;', 'begin', ' count:=count+1;', ' x:=3;', ' tpoint.x:=4;', ' fly;', ' tpoint.fly;', 'end;', 'var', ' r: specialize TPoint;', ' s: specialize TPoint;', 'begin', ' r.x:=10;', '']); ConvertProgram; CheckSource('TestGen_Class_ClassConstructor', LinesToStr([ // statements 'rtl.createClass($mod, "TObject", null, function () {', ' this.$init = function () {', ' };', ' this.$final = function () {', ' };', '});', 'rtl.createClass($mod, "TPoint$G1", $mod.TObject, function () {', ' this.x = 0;', ' this.Fly = function () {', ' };', '});', 'rtl.createClass($mod, "TPoint$G2", $mod.TObject, function () {', ' this.x = 0;', ' this.Fly = function () {', ' };', '});', 'this.count = 0;', 'this.r = null;', 'this.s = null;', '']), LinesToStr([ // $mod.$main '(function () {', ' $mod.count = $mod.count + 1;', ' $mod.TPoint$G1.x = 3;', ' $mod.TPoint$G1.x = 4;', ' $mod.TPoint$G1.Fly();', ' $mod.TPoint$G1.Fly();', '})();', '(function () {', ' $mod.count = $mod.count + 1;', ' $mod.TPoint$G2.x = 3;', ' $mod.TPoint$G2.x = 4;', ' $mod.TPoint$G2.Fly();', ' $mod.TPoint$G2.Fly();', '})();', '$mod.TPoint$G1.x = 10;', ''])); end; procedure TTestGenerics.TestGen_ExtClass_Array; begin StartProgram(false); Add([ '{$mode delphi}', '{$ModeSwitch externalclass}', 'type', ' NativeInt = longint;', ' TJSGenArray = Class external name ''Array''', ' private', ' function GetElements(Index: NativeInt): T; external name ''[]'';', ' procedure SetElements(Index: NativeInt; const AValue: T); external name ''[]'';', ' public', ' type TSelfType = TJSGenArray;', ' public', ' FLength : NativeInt; external name ''length'';', ' constructor new; overload;', ' constructor new(aLength : NativeInt); overload;', ' class function _of() : TSelfType; varargs; external name ''of'';', ' function fill(aValue : T) : TSelfType; overload;', ' function fill(aValue : T; aStartIndex : NativeInt) : TSelfType; overload;', ' function fill(aValue : T; aStartIndex,aEndIndex : NativeInt) : TSelfType; overload;', ' property Length : NativeInt Read FLength Write FLength;', ' property Elements[Index: NativeInt]: T read GetElements write SetElements; default;', ' end;', ' TJSWordArray = TJSGenArray;', 'var', ' wa: TJSWordArray;', ' w: word;', 'begin', ' wa:=TJSWordArray.new;', ' wa:=TJSWordArray.new(3);', ' wa:=TJSWordArray._of(4,5);', ' wa:=wa.fill(7);', ' wa:=wa.fill(7,8,9);', ' w:=wa.length;', ' wa.length:=10;', ' wa[11]:=w;', ' w:=wa[12];', '']); ConvertProgram; CheckSource('TestGen_ExtClass_Array', LinesToStr([ // statements 'this.wa = null;', 'this.w = 0;', '']), LinesToStr([ // $mod.$main '$mod.wa = new Array();', '$mod.wa = new Array(3);', '$mod.wa = Array.of(4, 5);', '$mod.wa = $mod.wa.fill(7);', '$mod.wa = $mod.wa.fill(7, 8, 9);', '$mod.w = $mod.wa.length;', '$mod.wa.length = 10;', '$mod.wa[11] = $mod.w;', '$mod.w = $mod.wa[12];', ''])); end; procedure TTestGenerics.TestGen_InlineSpec_Constructor; begin StartProgram(false); Add([ '{$mode objfpc}', 'type', ' TObject = class', ' public', ' constructor Create;', ' end;', ' generic TBird = class', ' end;', 'constructor TObject.Create; begin end;', 'var b: specialize TBird;', 'begin', ' b:=specialize TBird.Create;', '']); ConvertProgram; CheckSource('TestGen_InlineSpec_Constructor', LinesToStr([ // statements 'rtl.createClass($mod, "TObject", null, function () {', ' this.$init = function () {', ' };', ' this.$final = function () {', ' };', ' this.Create = function () {', ' return this;', ' };', '});', 'rtl.createClass($mod, "TBird$G1", $mod.TObject, function () {', '});', 'this.b = null;', '']), LinesToStr([ // $mod.$main '$mod.b = $mod.TBird$G1.$create("Create");', ''])); end; procedure TTestGenerics.TestGen_CallUnitImplProc; begin AddModuleWithIntfImplSrc('UnitA.pas', LinesToStr([ 'type', ' generic TBird = class', ' procedure Fly;', ' end;', 'var b: specialize TBird;', '']), LinesToStr([ 'procedure DoIt;', 'var b: specialize TBird;', 'begin', ' b:=specialize TBird.Create;', ' b.Fly;', 'end;', 'procedure TBird.Fly;', 'begin', ' DoIt;', 'end;', ''])); StartProgram(true,[supTObject]); Add('uses UnitA;'); Add('begin'); ConvertProgram; CheckUnit('UnitA.pas', LinesToStr([ // statements 'rtl.module("UnitA", ["system"], function () {', ' var $mod = this;', ' var $impl = $mod.$impl;', ' rtl.createClass($mod, "TBird$G1", pas.system.TObject, function () {', ' this.Fly = function () {', ' $impl.DoIt();', ' };', ' });', ' rtl.createClass($mod, "TBird$G2", pas.system.TObject, function () {', ' this.Fly = function () {', ' $impl.DoIt();', ' };', ' });', ' this.b = null;', '}, null, function () {', ' var $mod = this;', ' var $impl = $mod.$impl;', ' $impl.DoIt = function () {', ' var b = null;', ' b = $mod.TBird$G2.$create("Create");', ' b.Fly();', ' };', '});', ''])); end; procedure TTestGenerics.TestGen_IntAssignTemplVar; begin StartProgram(false); Add([ 'type', ' TObject = class end;', ' generic TBird = class', ' m: T;', ' procedure Fly;', ' end;', 'var b: specialize TBird;', 'procedure TBird.Fly;', 'var i: nativeint;', 'begin', ' i:=m;', 'end;', 'begin', '']); ConvertProgram; CheckSource('TestGen_IntAssignTemplVar', LinesToStr([ // statements 'rtl.createClass($mod, "TObject", null, function () {', ' this.$init = function () {', ' };', ' this.$final = function () {', ' };', '});', 'rtl.createClass($mod, "TBird$G1", $mod.TObject, function () {', ' this.$init = function () {', ' $mod.TObject.$init.call(this);', ' this.m = 0;', ' };', ' this.Fly = function () {', ' var i = 0;', ' i = this.m;', ' };', '});', 'this.b = null;', '']), LinesToStr([ // $mod.$main ''])); end; procedure TTestGenerics.TestGen_TypeCastDotField; begin StartProgram(false); Add([ 'type', ' TObject = class end;', ' generic TBird = class', ' Field: T;', ' procedure Fly;', ' end;', 'var', ' o: TObject;', ' b: specialize TBird;', 'procedure TBird.Fly;', 'begin', ' specialize TBird(o).Field:=3;', ' if 4=specialize TBird(o).Field then ;', 'end;', 'begin', ' specialize TBird(o).Field:=5;', ' if 6=specialize TBird(o).Field then ;', '']); ConvertProgram; CheckSource('TestGen_TypeCastDotField', LinesToStr([ // statements 'rtl.createClass($mod, "TObject", null, function () {', ' this.$init = function () {', ' };', ' this.$final = function () {', ' };', '});', 'rtl.createClass($mod, "TBird$G1", $mod.TObject, function () {', ' this.$init = function () {', ' $mod.TObject.$init.call(this);', ' this.Field = 0;', ' };', ' this.Fly = function () {', ' $mod.o.Field = 3;', ' if (4 === $mod.o.Field) ;', ' };', '});', 'this.o = null;', 'this.b = null;', '']), LinesToStr([ // $mod.$main '$mod.o.Field = 5;', 'if (6 === $mod.o.Field) ;', ''])); end; procedure TTestGenerics.TestGen_HelperForArray; begin StartProgram(false); Add([ '{$ModeSwitch typehelpers}', 'type', ' generic TArr = array[1..2] of T;', ' TWordArrHelper = type helper for specialize TArr', ' procedure Fly(w: word);', ' end;', 'procedure TWordArrHelper.Fly(w: word);', 'begin', 'end;', 'var', ' a: specialize TArr;', 'begin', ' a.Fly(3);', '']); ConvertProgram; CheckSource('TestGen_HelperForArray', LinesToStr([ // statements 'rtl.createHelper($mod, "TWordArrHelper", null, function () {', ' this.Fly = function (w) {', ' };', '});', 'this.a = rtl.arraySetLength(null, 0, 2);', '']), LinesToStr([ // $mod.$main '$mod.TWordArrHelper.Fly.call({', ' p: $mod,', ' get: function () {', ' return this.p.a;', ' },', ' set: function (v) {', ' this.p.a = v;', ' }', '}, 3);', ''])); end; procedure TTestGenerics.TestGenProc_Function_ObjFPC; begin StartProgram(false); Add([ 'generic function Run(a: T): T;', 'var i: T;', 'begin', ' a:=i;', ' Result:=a;', 'end;', 'var w: word;', 'begin', ' w:=specialize Run(3);', '']); ConvertProgram; CheckSource('TestGenProc_Function_ObjFPC', LinesToStr([ // statements 'this.Run$s0 = function (a) {', ' var Result = 0;', ' var i = 0;', ' a = i;', ' Result = a;', ' return Result;', '};', 'this.w = 0;', '']), LinesToStr([ // $mod.$main '$mod.w = $mod.Run$s0(3);', ''])); end; procedure TTestGenerics.TestGenProc_Function_Delphi; begin StartProgram(false); Add([ '{$mode delphi}', 'function Run(a: T): T;', 'var i: T;', 'begin', ' a:=i;', ' Result:=a;', 'end;', 'var w: word;', 'begin', ' w:=Run(3);', '']); ConvertProgram; CheckSource('TestGenProc_Function_Delphi', LinesToStr([ // statements 'this.Run$s0 = function (a) {', ' var Result = 0;', ' var i = 0;', ' a = i;', ' Result = a;', ' return Result;', '};', 'this.w = 0;', '']), LinesToStr([ // $mod.$main '$mod.w = $mod.Run$s0(3);', ''])); end; procedure TTestGenerics.TestGenProc_Overload; begin StartProgram(false); Add([ 'generic procedure DoIt(a: T; w: word); overload;', 'begin', 'end;', 'generic procedure DoIt(a: T; b: boolean); overload;', 'begin', 'end;', 'begin', ' specialize DoIt(3,4);', ' specialize DoIt(false,5);', ' specialize DoIt(6,true);', ' specialize DoIt(7.3,true);', '']); ConvertProgram; CheckSource('TestGenProc_Overload', LinesToStr([ // statements 'this.DoIt$s0 = function (a, w) {', '};', 'this.DoIt$s1 = function (a, w) {', '};', 'this.DoIt$1s0 = function (a, b) {', '};', 'this.DoIt$1s1 = function (a, b) {', '};', '']), LinesToStr([ // $mod.$main '$mod.DoIt$s0(3, 4);', '$mod.DoIt$s1(false, 5);', '$mod.DoIt$1s0(6, true);', '$mod.DoIt$1s1(7.3, true);', ''])); end; procedure TTestGenerics.TestGenProc_Forward; begin StartProgram(false); Add([ '{$mode delphi}', 'procedure Run(a: S; b: boolean); forward;', 'procedure Run(a: S; b: boolean);', 'begin', ' Run(1,true);', 'end;', 'begin', ' Run(1.3,true);', '']); ConvertProgram; CheckSource('TestGenProc_infer_OverloadForward', LinesToStr([ // statements 'this.Run$s0 = function (a, b) {', ' $mod.Run$s0(1, true);', '};', 'this.Run$s1 = function (a, b) {', ' $mod.Run$s0(1, true);', '};', '']), LinesToStr([ // $mod.$main '$mod.Run$s1(1.3, true);', ''])); end; procedure TTestGenerics.TestGenProc_Infer_OverloadForward; begin StartProgram(false); Add([ '{$mode delphi}', 'procedure {#A}Run(a: S; b: boolean); forward; overload;', 'procedure {#B}Run(a: T; w: word); forward; overload;', 'procedure {#C}Run(a: U; b: U); forward; overload;', 'procedure {#A2}Run(a: S; b: boolean); overload;', 'begin', ' {@A}Run(1,true);', // non generic take precedence ' {@B}Run(2,word(3));', // non generic take precedence ' {@C}Run(''foo'',''bar'');', 'end;', 'procedure {#B2}Run(a: T; w: word); overload;', 'begin', 'end;', 'procedure {#C2}Run(a: U; b: U); overload;', 'begin', 'end;', 'begin', ' {@A}Run(1,true);', // non generic take precedence ' {@B}Run(2,word(3));', // non generic take precedence ' {@C}Run(''foo'',''bar'');', '']); ConvertProgram; CheckSource('TestGenProc_infer_OverloadForward', LinesToStr([ // statements 'this.Run$s0 = function (a, b) {', ' $mod.Run$s0(1, true);', ' $mod.Run$1s0(2, 3);', ' $mod.Run$2s0("foo", "bar");', '};', 'this.Run$1s0 = function (a, w) {', '};', 'this.Run$2s0 = function (a, b) {', '};', '']), LinesToStr([ // $mod.$main '$mod.Run$s0(1, true);', '$mod.Run$1s0(2, 3);', '$mod.Run$2s0("foo", "bar");', ''])); end; procedure TTestGenerics.TestGenProc_TypeInfo; begin Converter.Options:=Converter.Options-[coNoTypeInfo]; StartProgram(true,[supTypeInfo]); Add([ '{$modeswitch implicitfunctionspecialization}', 'generic procedure Run(a: S);', 'var', ' p: TTypeInfo;', 'begin', ' p:=TypeInfo(S);', ' p:=TypeInfo(a);', 'end;', 'begin', ' Run(word(3));', ' Run(''foo'');', '']); ConvertProgram; CheckSource('TestGenProc_TypeInfo', LinesToStr([ // statements 'this.Run$s0 = function (a) {', ' var p = null;', ' p = rtl.word;', ' p = rtl.word;', '};', 'this.Run$s1 = function (a) {', ' var p = null;', ' p = rtl.string;', ' p = rtl.string;', '};', '']), LinesToStr([ // $mod.$main '$mod.Run$s0(3);', '$mod.Run$s1("foo");', ''])); end; procedure TTestGenerics.TestGenProc_Infer_Widen; begin StartProgram(false); Add([ '{$mode delphi}', 'procedure Run(a: S; b: S);', 'begin', 'end;', 'begin', ' Run(word(1),longint(2));', ' Run(byte(2),smallint(2));', ' Run(longword(3),longint(2));', ' Run(nativeint(4),longint(2));', ' Run(nativeint(5),nativeuint(2));', ' Run(''a'',''foo'');', ' Run(''bar'',''c'');', '']); ConvertProgram; CheckSource('TestGenProc_Infer_Widen', LinesToStr([ // statements 'this.Run$s0 = function (a, b) {', '};', 'this.Run$s1 = function (a, b) {', '};', 'this.Run$s2 = function (a, b) {', '};', '']), LinesToStr([ // $mod.$main '$mod.Run$s0(1, 2);', '$mod.Run$s0(2, 2);', '$mod.Run$s1(3, 2);', '$mod.Run$s1(4, 2);', '$mod.Run$s1(5, 2);', '$mod.Run$s2("a", "foo");', '$mod.Run$s2("bar", "c");', ''])); end; procedure TTestGenerics.TestGenProc_Infer_PassAsArg; begin StartProgram(false); Add([ '{$mode delphi}', 'function Run(a: T): T;', 'var b: T;', 'begin', ' Run(Run(3));', ' Run(Run(word(4)));', 'end;', 'begin', ' Run(Run(5));', ' Run(Run(word(6)));', '']); ConvertProgram; CheckSource('TestGenProc_Infer_PassAsArg', LinesToStr([ // statements 'this.Run$s0 = function (a) {', ' var Result = 0;', ' var b = 0;', ' $mod.Run$s0($mod.Run$s0(3));', ' $mod.Run$s0($mod.Run$s0(4));', ' return Result;', '};', '']), LinesToStr([ // $mod.$main '$mod.Run$s0($mod.Run$s0(5));', '$mod.Run$s0($mod.Run$s0(6));', ''])); end; procedure TTestGenerics.TestGenMethod_ObjFPC; begin StartProgram(false); Add([ '{$mode objfpc}', '{$ModeSwitch implicitfunctionspecialization}', 'type', ' TObject = class', ' generic procedure {#A}Run(a: S; b: boolean); overload;', ' generic procedure {#B}Run(a: T; w: word); overload;', ' generic procedure {#C}Run(a: U; b: U); overload;', ' end; ', 'generic procedure {#A2}TObject.Run(a: S; b: boolean); overload;', 'begin', ' {@A}Run(1,true);', // non generic take precedence ' {@B}Run(2,word(3));', // non generic take precedence ' {@C}Run(''foo'',''bar'');', 'end;', 'generic procedure {#B2}TObject.Run(a: T; w: word); overload;', 'begin', 'end;', 'generic procedure {#C2}TObject.Run(a: U; b: U); overload;', 'begin', 'end;', 'var o: TObject;', 'begin', ' o.{@A}Run(1,true);', // non generic take precedence ' o.{@B}Run(2,word(3));', // non generic take precedence ' o.{@C}Run(''foo'',''bar'');', '']); ConvertProgram; CheckSource('TestGenMethod_ObjFPC', LinesToStr([ // statements 'rtl.createClass($mod, "TObject", null, function () {', ' this.$init = function () {', ' };', ' this.$final = function () {', ' };', ' this.Run$s0 = function (a, b) {', ' this.Run$s0(1, true);', ' this.Run$1s0(2, 3);', ' this.Run$2s0("foo", "bar");', ' };', ' this.Run$1s0 = function (a, w) {', ' };', ' this.Run$2s0 = function (a, b) {', ' };', '});', 'this.o = null;', '']), LinesToStr([ // $mod.$main '$mod.o.Run$s0(1, true);', '$mod.o.Run$1s0(2, 3);', '$mod.o.Run$2s0("foo", "bar");', ''])); end; Initialization RegisterTests([TTestGenerics]); end.