Browse Source

pastojs: helper: class property with static class method

git-svn-id: trunk@41256 -
Mattias Gaertner 6 years ago
parent
commit
fcc78d311b
2 changed files with 493 additions and 15 deletions
  1. 9 9
      packages/pastojs/src/fppas2js.pp
  2. 484 6
      packages/pastojs/tests/tcmodules.pas

+ 9 - 9
packages/pastojs/src/fppas2js.pp

@@ -15478,7 +15478,7 @@ begin
     exit;
     end;
   IsHelper:=aResolver.IsHelper(Proc.Parent);
-  NeedClass:=aResolver.IsClassMethod(Proc);
+  NeedClass:=aResolver.IsClassMethod(Proc) and not Proc.IsStatic;
 
   // an of-object method -> create "rtl.createCallback(Target,func)"
   TargetJS:=nil;
@@ -15872,14 +15872,13 @@ begin
   if Decl is TPasFunction then
     begin
     // call function
-    if (Expr<>nil) then
+    if aResolver.IsHelper(Decl.Parent) then
       begin
-      // explicit property read
-      if aResolver.IsHelper(Decl.Parent) then
-        begin
-        Result:=CreateCallHelperMethod(TPasProcedure(Decl),Expr,AContext);
-        exit;
-        end;
+      if (Expr=nil) then
+        // implicit property read, e.g. enumerator property Current
+        RaiseNotSupported(PosEl,AContext,20190208111355,GetObjName(Prop));
+      Result:=CreateCallHelperMethod(TPasProcedure(Decl),Expr,AContext);
+      exit;
       end;
     Call:=CreateCallExpression(PosEl);
     try
@@ -19848,7 +19847,8 @@ begin
         end
       else if IsClassFunction(El) then
         begin
-        if Dot.Resolver.ResolvedElIsClassOrRecordInstance(Dot.LeftResolved) then
+        if (not TPasProcedure(El).IsStatic)
+            and Dot.Resolver.ResolvedElIsClassOrRecordInstance(Dot.LeftResolved) then
           // accessing a class method from an object, 'this' must be the class/record
           Append_GetClass(El);
         end;

+ 484 - 6
packages/pastojs/tests/tcmodules.pas

@@ -641,9 +641,9 @@ type
     Procedure TestClassHelper_Property_Array;
     Procedure TestClassHelper_Property_Array_Default;
     Procedure TestClassHelper_Property_Array_DefaultDefault;
-    // todo: TestClassHelper_ClassProperty  static/nonstatic
-    // todo: TestClassHelper_ClassProperty_Array
-    // todo: TestClassHelper_Overload
+    Procedure TestClassHelper_ClassProperty;
+    Procedure TestClassHelper_ClassPropertyStatic;
+    Procedure TestClassHelper_ClassProperty_Array;
     // todo: TestClassHelper_ForIn
     // todo: TestRecordHelper_ClassVar
     // todo: TestRecordHelper_Method
@@ -10479,9 +10479,9 @@ begin
     '$mod.TRec.SetInt($mod.TRec.GetInt() + 2);',
     '$mod.TRec.SetInt($mod.TRec.Fx);',
     '$mod.TRec.Fy = $mod.r.Fx + 1;',
-    'if ($mod.r.$record.GetInt() === 2) ;',
-    '$mod.r.$record.SetInt($mod.r.$record.GetInt() + 2);',
-    '$mod.r.$record.SetInt($mod.r.Fx);',
+    'if ($mod.r.GetInt() === 2) ;',
+    '$mod.r.SetInt($mod.r.GetInt() + 2);',
+    '$mod.r.SetInt($mod.r.Fx);',
     '']));
 end;
 
@@ -19783,6 +19783,484 @@ begin
     '']));
 end;
 
+procedure TTestModule.TestClassHelper_ClassProperty;
+begin
+  StartProgram(false);
+  Add([
+  'type',
+  '  TObject = class',
+  '    class var FSize: word;',
+  '    class function GetSpeed: word;',
+  '    class procedure SetSpeed(Value: word); virtual; abstract;',
+  '  end;',
+  '  TObjHelper = class helper for TObject',
+  '    class function GetLeft: word;',
+  '    class procedure SetLeft(Value: word);',
+  '    class property Size: word read FSize write FSize;',
+  '    class property Speed: word read GetSpeed write SetSpeed;',
+  '    class property Left: word read GetLeft write SetLeft;',
+  '  end;',
+  '  TBird = class',
+  '    class property NotRight: word read GetLeft write SetLeft;',
+  '    class procedure DoIt;',
+  '  end;',
+  '  TBirdClass = class of TBird;',
+  'class function Tobject.GetSpeed: word;',
+  'begin',
+  '  Size:=Size+11;',
+  '  Speed:=Speed+12;',
+  '  Left:=Left+13;',
+  '  Self.Size:=Self.Size+21;',
+  '  Self.Speed:=Self.Speed+22;',
+  '  Self.Left:=Self.Left+23;',
+  '  with Self do begin',
+  '    Size:=Size+31;',
+  '    Speed:=Speed+32;',
+  '    Left:=Left+33;',
+  '  end;',
+  'end;',
+  'class function TObjHelper.GetLeft: word;',
+  'begin',
+  '  Size:=Size+11;',
+  '  Speed:=Speed+12;',
+  '  Left:=Left+13;',
+  '  Self.Size:=Self.Size+21;',
+  '  Self.Speed:=Self.Speed+22;',
+  '  Self.Left:=Self.Left+23;',
+  '  with Self do begin',
+  '    Size:=Size+31;',
+  '    Speed:=Speed+32;',
+  '    Left:=Left+33;',
+  '  end;',
+  'end;',
+  'class procedure TObjHelper.SetLeft(Value: word);',
+  'begin',
+  'end;',
+  'class procedure TBird.DoIt;',
+  'begin',
+  '  NotRight:=NotRight+11;',
+  '  Self.NotRight:=Self.NotRight+21;',
+  '  with Self do NotRight:=NotRight+31;',
+  'end;',
+  'var',
+  '  b: TBird;',
+  '  c: TBirdClass;',
+  'begin',
+  '  b.Size:=b.Size+11;',
+  '  b.Speed:=b.Speed+12;',
+  '  b.Left:=b.Left+13;',
+  '  b.NotRight:=b.NotRight+14;',
+  '  with b do begin',
+  '    Size:=Size+31;',
+  '    Speed:=Speed+32;',
+  '    Left:=Left+33;',
+  '    NotRight:=NotRight+34;',
+  '  end;',
+  '  c.Size:=c.Size+11;',
+  '  c.Speed:=c.Speed+12;',
+  '  c.Left:=c.Left+13;',
+  '  c.NotRight:=c.NotRight+14;',
+  '  with c do begin',
+  '    Size:=Size+31;',
+  '    Speed:=Speed+32;',
+  '    Left:=Left+33;',
+  '    NotRight:=NotRight+34;',
+  '  end;',
+  '  tbird.Size:=tbird.Size+11;',
+  '  tbird.Speed:=tbird.Speed+12;',
+  '  tbird.Left:=tbird.Left+13;',
+  '  tbird.NotRight:=tbird.NotRight+14;',
+  '  with tbird do begin',
+  '    Size:=Size+31;',
+  '    Speed:=Speed+32;',
+  '    Left:=Left+33;',
+  '    NotRight:=NotRight+34;',
+  '  end;',
+  '']);
+  ConvertProgram;
+  CheckSource('TestClassHelper_ClassProperty',
+    LinesToStr([ // statements
+    'rtl.createClass($mod, "TObject", null, function () {',
+    '  this.FSize = 0;',
+    '  this.$init = function () {',
+    '  };',
+    '  this.$final = function () {',
+    '  };',
+    '  this.GetSpeed = function () {',
+    '    var Result = 0;',
+    '    $mod.TObject.FSize = this.FSize + 11;',
+    '    this.SetSpeed(this.GetSpeed() + 12);',
+    '    $mod.TObjHelper.SetLeft.apply(this, $mod.TObjHelper.GetLeft.apply(this) + 13);',
+    '    $mod.TObject.FSize = this.FSize + 21;',
+    '    this.SetSpeed(this.GetSpeed() + 22);',
+    '    $mod.TObjHelper.SetLeft.apply(this, $mod.TObjHelper.GetLeft.apply(this) + 23);',
+    '    $mod.TObject.FSize = this.FSize + 31;',
+    '    this.SetSpeed(this.GetSpeed() + 32);',
+    '    $mod.TObjHelper.SetLeft.apply(this, $mod.TObjHelper.GetLeft.apply(this) + 33);',
+    '    return Result;',
+    '  };',
+    '});',
+    'rtl.createHelper($mod, "TObjHelper", null, function () {',
+    '  this.GetLeft = function () {',
+    '    var Result = 0;',
+    '    $mod.TObject.FSize = this.FSize + 11;',
+    '    this.SetSpeed(this.GetSpeed() + 12);',
+    '    $mod.TObjHelper.SetLeft.apply(this, $mod.TObjHelper.GetLeft.apply(this) + 13);',
+    '    $mod.TObject.FSize = this.FSize + 21;',
+    '    this.SetSpeed(this.GetSpeed() + 22);',
+    '    $mod.TObjHelper.SetLeft.apply(this, $mod.TObjHelper.GetLeft.apply(this) + 23);',
+    '    $mod.TObject.FSize = this.FSize + 31;',
+    '    this.SetSpeed(this.GetSpeed() + 32);',
+    '    $mod.TObjHelper.SetLeft.apply(this, $mod.TObjHelper.GetLeft.apply(this) + 33);',
+    '    return Result;',
+    '  };',
+    '  this.SetLeft = function (Value) {',
+    '  };',
+    '});',
+    'rtl.createClass($mod, "TBird", $mod.TObject, function () {',
+    '  this.DoIt = function () {',
+    '    $mod.TObjHelper.SetLeft.apply(this, $mod.TObjHelper.GetLeft.apply(this) + 11);',
+    '    $mod.TObjHelper.SetLeft.apply(this, $mod.TObjHelper.GetLeft.apply(this) + 21);',
+    '    $mod.TObjHelper.SetLeft.apply(this, $mod.TObjHelper.GetLeft.apply(this) + 31);',
+    '  };',
+    '});',
+    'this.b = null;',
+    'this.c = null;',
+    '']),
+    LinesToStr([ // $mod.$main
+    '$mod.TObject.FSize = $mod.b.FSize + 11;',
+    '$mod.b.$class.SetSpeed($mod.b.$class.GetSpeed() + 12);',
+    '$mod.TObjHelper.SetLeft.apply($mod.b.$class, $mod.TObjHelper.GetLeft.apply($mod.b.$class) + 13);',
+    '$mod.TObjHelper.SetLeft.apply($mod.b.$class, $mod.TObjHelper.GetLeft.apply($mod.b.$class) + 14);',
+    'var $with1 = $mod.b;',
+    '$mod.TObject.FSize = $with1.FSize + 31;',
+    '$with1.SetSpeed($with1.GetSpeed() + 32);',
+    '$mod.TObjHelper.SetLeft.apply($with1.$class, $mod.TObjHelper.GetLeft.apply($with1.$class) + 33);',
+    '$mod.TObjHelper.SetLeft.apply($with1.$class, $mod.TObjHelper.GetLeft.apply($with1.$class) + 34);',
+    '$mod.TObject.FSize = $mod.c.FSize + 11;',
+    '$mod.c.SetSpeed($mod.c.GetSpeed() + 12);',
+    '$mod.TObjHelper.SetLeft.apply($mod.c, $mod.TObjHelper.GetLeft.apply($mod.c) + 13);',
+    '$mod.TObjHelper.SetLeft.apply($mod.c, $mod.TObjHelper.GetLeft.apply($mod.c) + 14);',
+    'var $with2 = $mod.c;',
+    '$mod.TObject.FSize = $with2.FSize + 31;',
+    '$with2.SetSpeed($with2.GetSpeed() + 32);',
+    '$mod.TObjHelper.SetLeft.apply($with2, $mod.TObjHelper.GetLeft.apply($with2) + 33);',
+    '$mod.TObjHelper.SetLeft.apply($with2, $mod.TObjHelper.GetLeft.apply($with2) + 34);',
+    '$mod.TObject.FSize = $mod.TBird.FSize + 11;',
+    '$mod.TBird.SetSpeed($mod.TBird.GetSpeed() + 12);',
+    '$mod.TObjHelper.SetLeft.apply($mod.TBird, $mod.TObjHelper.GetLeft.apply($mod.TBird) + 13);',
+    '$mod.TObjHelper.SetLeft.apply($mod.TBird, $mod.TObjHelper.GetLeft.apply($mod.TBird) + 14);',
+    'var $with3 = $mod.TBird;',
+    '$mod.TObject.FSize = $with3.FSize + 31;',
+    '$with3.SetSpeed($with3.GetSpeed() + 32);',
+    '$mod.TObjHelper.SetLeft.apply($mod.TBird, $mod.TObjHelper.GetLeft.apply($mod.TBird) + 33);',
+    '$mod.TObjHelper.SetLeft.apply($mod.TBird, $mod.TObjHelper.GetLeft.apply($mod.TBird) + 34);',
+    '']));
+end;
+
+procedure TTestModule.TestClassHelper_ClassPropertyStatic;
+begin
+  StartProgram(false);
+  Add([
+  'type',
+  '  TObject = class',
+  '    class function GetSpeed: word; static;',
+  '    class procedure SetSpeed(Value: word); static;',
+  '  end;',
+  '  TObjHelper = class helper for TObject',
+  '    class function GetLeft: word; static;',
+  '    class procedure SetLeft(Value: word); static;',
+  '    class property Speed: word read GetSpeed write SetSpeed;',
+  '    class property Left: word read GetLeft write SetLeft;',
+  '  end;',
+  '  TBird = class',
+  '    class property NotRight: word read GetLeft write SetLeft;',
+  '    class procedure DoIt; static;',
+  '    class procedure DoSome;',
+  '  end;',
+  '  TBirdClass = class of TBird;',
+  'class function Tobject.GetSpeed: word;',
+  'begin',
+  '  Speed:=Speed+12;',
+  '  Left:=Left+13;',
+  'end;',
+  'class procedure TObject.SetSpeed(Value: word);',
+  'begin',
+  'end;',
+  'class function TObjHelper.GetLeft: word;',
+  'begin',
+  '  Speed:=Speed+12;',
+  '  Left:=Left+13;',
+  'end;',
+  'class procedure TObjHelper.SetLeft(Value: word);',
+  'begin',
+  'end;',
+  'class procedure TBird.DoIt;',
+  'begin',
+  '  NotRight:=NotRight+11;',
+  'end;',
+  'class procedure TBird.DoSome;',
+  'begin',
+  '  Speed:=Speed+12;',
+  '  Left:=Left+13;',
+  '  Self.Speed:=Self.Speed+22;',
+  '  Self.Left:=Self.Left+23;',
+  '  with Self do begin',
+  '    Speed:=Speed+32;',
+  '    Left:=Left+33;',
+  '  end;',
+  '  NotRight:=NotRight+11;',
+  '  Self.NotRight:=Self.NotRight+21;',
+  '  with Self do NotRight:=NotRight+31;',
+  'end;',
+  'var',
+  '  b: TBird;',
+  '  c: TBirdClass;',
+  'begin',
+  '  b.Speed:=b.Speed+12;',
+  '  b.Left:=b.Left+13;',
+  '  b.NotRight:=b.NotRight+14;',
+  '  with b do begin',
+  '    Speed:=Speed+32;',
+  '    Left:=Left+33;',
+  '    NotRight:=NotRight+34;',
+  '  end;',
+  '  c.Speed:=c.Speed+12;',
+  '  c.Left:=c.Left+13;',
+  '  c.NotRight:=c.NotRight+14;',
+  '  with c do begin',
+  '    Speed:=Speed+32;',
+  '    Left:=Left+33;',
+  '    NotRight:=NotRight+34;',
+  '  end;',
+  '  tbird.Speed:=tbird.Speed+12;',
+  '  tbird.Left:=tbird.Left+13;',
+  '  tbird.NotRight:=tbird.NotRight+14;',
+  '  with tbird do begin',
+  '    Speed:=Speed+32;',
+  '    Left:=Left+33;',
+  '    NotRight:=NotRight+34;',
+  '  end;',
+  '']);
+  ConvertProgram;
+  CheckSource('TestClassHelper_ClassPropertyStatic',
+    LinesToStr([ // statements
+    'rtl.createClass($mod, "TObject", null, function () {',
+    '  this.$init = function () {',
+    '  };',
+    '  this.$final = function () {',
+    '  };',
+    '  this.GetSpeed = function () {',
+    '    var Result = 0;',
+    '    this.SetSpeed(this.GetSpeed() + 12);',
+    '    $mod.TObjHelper.SetLeft($mod.TObjHelper.GetLeft() + 13);',
+    '    return Result;',
+    '  };',
+    '  this.SetSpeed = function (Value) {',
+    '  };',
+    '});',
+    'rtl.createHelper($mod, "TObjHelper", null, function () {',
+    '  this.GetLeft = function () {',
+    '    var Result = 0;',
+    '    this.SetSpeed(this.GetSpeed() + 12);',
+    '    $mod.TObjHelper.SetLeft($mod.TObjHelper.GetLeft() + 13);',
+    '    return Result;',
+    '  };',
+    '  this.SetLeft = function (Value) {',
+    '  };',
+    '});',
+    'rtl.createClass($mod, "TBird", $mod.TObject, function () {',
+    '  this.DoIt = function () {',
+    '    $mod.TObjHelper.SetLeft($mod.TObjHelper.GetLeft() + 11);',
+    '  };',
+    '  this.DoSome = function () {',
+    '    this.SetSpeed(this.GetSpeed() + 12);',
+    '    $mod.TObjHelper.SetLeft($mod.TObjHelper.GetLeft() + 13);',
+    '    this.SetSpeed(this.GetSpeed() + 22);',
+    '    $mod.TObjHelper.SetLeft($mod.TObjHelper.GetLeft() + 23);',
+    '    this.SetSpeed(this.GetSpeed() + 32);',
+    '    $mod.TObjHelper.SetLeft($mod.TObjHelper.GetLeft() + 33);',
+    '    $mod.TObjHelper.SetLeft($mod.TObjHelper.GetLeft() + 11);',
+    '    $mod.TObjHelper.SetLeft($mod.TObjHelper.GetLeft() + 21);',
+    '    $mod.TObjHelper.SetLeft($mod.TObjHelper.GetLeft() + 31);',
+    '  };',
+    '});',
+    'this.b = null;',
+    'this.c = null;',
+    '']),
+    LinesToStr([ // $mod.$main
+    '$mod.b.SetSpeed($mod.b.GetSpeed() + 12);',
+    '$mod.TObjHelper.SetLeft($mod.TObjHelper.GetLeft() + 13);',
+    '$mod.TObjHelper.SetLeft($mod.TObjHelper.GetLeft() + 14);',
+    'var $with1 = $mod.b;',
+    '$with1.SetSpeed($with1.GetSpeed() + 32);',
+    '$mod.TObjHelper.SetLeft($mod.TObjHelper.GetLeft() + 33);',
+    '$mod.TObjHelper.SetLeft($mod.TObjHelper.GetLeft() + 34);',
+    '$mod.c.SetSpeed($mod.c.GetSpeed() + 12);',
+    '$mod.TObjHelper.SetLeft($mod.TObjHelper.GetLeft() + 13);',
+    '$mod.TObjHelper.SetLeft($mod.TObjHelper.GetLeft() + 14);',
+    'var $with2 = $mod.c;',
+    '$with2.SetSpeed($with2.GetSpeed() + 32);',
+    '$mod.TObjHelper.SetLeft($mod.TObjHelper.GetLeft() + 33);',
+    '$mod.TObjHelper.SetLeft($mod.TObjHelper.GetLeft() + 34);',
+    '$mod.TBird.SetSpeed($mod.TBird.GetSpeed() + 12);',
+    '$mod.TObjHelper.SetLeft($mod.TObjHelper.GetLeft() + 13);',
+    '$mod.TObjHelper.SetLeft($mod.TObjHelper.GetLeft() + 14);',
+    'var $with3 = $mod.TBird;',
+    '$with3.SetSpeed($with3.GetSpeed() + 32);',
+    '$mod.TObjHelper.SetLeft($mod.TObjHelper.GetLeft() + 33);',
+    '$mod.TObjHelper.SetLeft($mod.TObjHelper.GetLeft() + 34);',
+    '']));
+end;
+
+procedure TTestModule.TestClassHelper_ClassProperty_Array;
+begin
+  StartProgram(false);
+  Add([
+  'type',
+  '  TObject = class',
+  '    class function GetSpeed(Index: boolean): word;',
+  '    class procedure SetSpeed(Index: boolean; Value: word); virtual; abstract;',
+  '  end;',
+  '  TObjHelper = class helper for TObject',
+  '    class function GetSize(Index: boolean): word;',
+  '    class procedure SetSize(Index: boolean; Value: word);',
+  '    class property Size[Index: boolean]: word read GetSize write SetSize;',
+  '    class property Speed[Index: boolean]: word read GetSpeed write SetSpeed;',
+  '  end;',
+  '  TBird = class',
+  '    class property Items[Index: boolean]: word read GetSize write SetSize;',
+  '    class procedure DoIt;',
+  '  end;',
+  '  TBirdClass = class of TBird;',
+  'class function Tobject.GetSpeed(Index: boolean): word;',
+  'begin',
+  '  Size[true]:=Size[false]+11;',
+  '  Speed[true]:=Speed[false]+12;',
+  '  Self.Size[true]:=Self.Size[false]+21;',
+  '  Self.Speed[true]:=Self.Speed[false]+22;',
+  '  with Self do begin',
+  '    Size[true]:=Size[false]+31;',
+  '    Speed[true]:=Speed[false]+32;',
+  '  end;',
+  'end;',
+  'class function TObjHelper.GetSize(Index: boolean): word;',
+  'begin',
+  '  Size[true]:=Size[false]+11;',
+  '  Speed[true]:=Speed[false]+12;',
+  '  Self.Size[true]:=Self.Size[false]+21;',
+  '  Self.Speed[true]:=Self.Speed[false]+22;',
+  '  with Self do begin',
+  '    Size[true]:=Size[false]+31;',
+  '    Speed[true]:=Speed[false]+32;',
+  '  end;',
+  'end;',
+  'class procedure TObjHelper.SetSize(Index: boolean; Value: word);',
+  'begin',
+  'end;',
+  'class procedure TBird.DoIt;',
+  'begin',
+  '  Items[true]:=Items[false]+11;',
+  '  Self.Items[true]:=Self.Items[false]+21;',
+  '  with Self do Items[true]:=Items[false]+31;',
+  'end;',
+  'var',
+  '  b: TBird;',
+  '  c: TBirdClass;',
+  'begin',
+  '  b.Size[true]:=b.Size[false]+11;',
+  '  b.Speed[true]:=b.Speed[false]+12;',
+  '  b.Items[true]:=b.Items[false]+13;',
+  '  with b do begin',
+  '    Size[true]:=Size[false]+21;',
+  '    Speed[true]:=Speed[false]+22;',
+  '    Items[true]:=Items[false]+23;',
+  '  end;',
+  '  c.Size[true]:=c.Size[false]+11;',
+  '  c.Speed[true]:=c.Speed[false]+12;',
+  '  c.Items[true]:=c.Items[false]+13;',
+  '  with c do begin',
+  '    Size[true]:=Size[false]+21;',
+  '    Speed[true]:=Speed[false]+22;',
+  '    Items[true]:=Items[false]+23;',
+  '  end;',
+  '  TBird.Size[true]:=TBird.Size[false]+11;',
+  '  TBird.Speed[true]:=TBird.Speed[false]+12;',
+  '  TBird.Items[true]:=TBird.Items[false]+13;',
+  '  with TBird do begin',
+  '    Size[true]:=Size[false]+21;',
+  '    Speed[true]:=Speed[false]+22;',
+  '    Items[true]:=Items[false]+23;',
+  '  end;',
+  '']);
+  ConvertProgram;
+  CheckSource('TestClassHelper_ClassProperty_Array',
+    LinesToStr([ // statements
+    'rtl.createClass($mod, "TObject", null, function () {',
+    '  this.$init = function () {',
+    '  };',
+    '  this.$final = function () {',
+    '  };',
+    '  this.GetSpeed = function (Index) {',
+    '    var Result = 0;',
+    '    $mod.TObjHelper.SetSize.apply(this, true, $mod.TObjHelper.GetSize.apply(this, false) + 11);',
+    '    this.SetSpeed(true, this.GetSpeed(false) + 12);',
+    '    $mod.TObjHelper.SetSize.apply(this, true, $mod.TObjHelper.GetSize.apply(this, false) + 21);',
+    '    this.SetSpeed(true, this.GetSpeed(false) + 22);',
+    '    $mod.TObjHelper.SetSize.apply(this, true, $mod.TObjHelper.GetSize.apply(this, false) + 31);',
+    '    this.SetSpeed(true, this.GetSpeed(false) + 32);',
+    '    return Result;',
+    '  };',
+    '});',
+    'rtl.createHelper($mod, "TObjHelper", null, function () {',
+    '  this.GetSize = function (Index) {',
+    '    var Result = 0;',
+    '    $mod.TObjHelper.SetSize.apply(this, true, $mod.TObjHelper.GetSize.apply(this, false) + 11);',
+    '    this.SetSpeed(true, this.GetSpeed(false) + 12);',
+    '    $mod.TObjHelper.SetSize.apply(this, true, $mod.TObjHelper.GetSize.apply(this, false) + 21);',
+    '    this.SetSpeed(true, this.GetSpeed(false) + 22);',
+    '    $mod.TObjHelper.SetSize.apply(this, true, $mod.TObjHelper.GetSize.apply(this, false) + 31);',
+    '    this.SetSpeed(true, this.GetSpeed(false) + 32);',
+    '    return Result;',
+    '  };',
+    '  this.SetSize = function (Index, Value) {',
+    '  };',
+    '});',
+    'rtl.createClass($mod, "TBird", $mod.TObject, function () {',
+    '  this.DoIt = function () {',
+    '    $mod.TObjHelper.SetSize.apply(this, true, $mod.TObjHelper.GetSize.apply(this, false) + 11);',
+    '    $mod.TObjHelper.SetSize.apply(this, true, $mod.TObjHelper.GetSize.apply(this, false) + 21);',
+    '    $mod.TObjHelper.SetSize.apply(this, true, $mod.TObjHelper.GetSize.apply(this, false) + 31);',
+    '  };',
+    '});',
+    'this.b = null;',
+    'this.c = null;',
+    '']),
+    LinesToStr([ // $mod.$main
+    '$mod.TObjHelper.SetSize.apply($mod.b.$class, true, $mod.TObjHelper.GetSize.apply($mod.b.$class, false) + 11);',
+    '$mod.b.$class.SetSpeed(true, $mod.b.$class.GetSpeed(false) + 12);',
+    '$mod.TObjHelper.SetSize.apply($mod.b.$class, true, $mod.TObjHelper.GetSize.apply($mod.b.$class, false) + 13);',
+    'var $with1 = $mod.b;',
+    '$mod.TObjHelper.SetSize.apply($with1.$class, true, $mod.TObjHelper.GetSize.apply($with1.$class, false) + 21);',
+    '$with1.SetSpeed(true, $with1.GetSpeed(false) + 22);',
+    '$mod.TObjHelper.SetSize.apply($with1.$class, true, $mod.TObjHelper.GetSize.apply($with1.$class, false) + 23);',
+    '$mod.TObjHelper.SetSize.apply($mod.c, true, $mod.TObjHelper.GetSize.apply($mod.c, false) + 11);',
+    '$mod.c.SetSpeed(true, $mod.c.GetSpeed(false) + 12);',
+    '$mod.TObjHelper.SetSize.apply($mod.c, true, $mod.TObjHelper.GetSize.apply($mod.c, false) + 13);',
+    'var $with2 = $mod.c;',
+    '$mod.TObjHelper.SetSize.apply($with2, true, $mod.TObjHelper.GetSize.apply($with2, false) + 21);',
+    '$with2.SetSpeed(true, $with2.GetSpeed(false) + 22);',
+    '$mod.TObjHelper.SetSize.apply($with2, true, $mod.TObjHelper.GetSize.apply($with2, false) + 23);',
+    '$mod.TObjHelper.SetSize.apply($mod.TBird, true, $mod.TObjHelper.GetSize.apply($mod.TBird, false) + 11);',
+    '$mod.TBird.SetSpeed(true, $mod.TBird.GetSpeed(false) + 12);',
+    '$mod.TObjHelper.SetSize.apply($mod.TBird, true, $mod.TObjHelper.GetSize.apply($mod.TBird, false) + 13);',
+    'var $with3 = $mod.TBird;',
+    '$mod.TObjHelper.SetSize.apply($mod.TBird, true, $mod.TObjHelper.GetSize.apply($mod.TBird, false) + 21);',
+    '$with3.SetSpeed(true, $with3.GetSpeed(false) + 22);',
+    '$mod.TObjHelper.SetSize.apply($mod.TBird, true, $mod.TObjHelper.GetSize.apply($mod.TBird, false) + 23);',
+    '']));
+end;
+
 procedure TTestModule.TestProcType;
 begin
   StartProgram(false);