Browse Source

pastojs: nested classes

git-svn-id: trunk@38878 -
Mattias Gaertner 7 years ago
parent
commit
8100f9b222

+ 118 - 65
packages/pastojs/src/fppas2js.pp

@@ -2308,8 +2308,6 @@ end;
 procedure TPas2JSResolver.AddType(El: TPasType);
 procedure TPas2JSResolver.AddType(El: TPasType);
 begin
 begin
   inherited AddType(El);
   inherited AddType(El);
-  if (El.Name<>'') and (TopScope is TPasClassScope) then
-    RaiseNotYetImplemented(20170608232534,El,'nested types');
 end;
 end;
 
 
 procedure TPas2JSResolver.ResolveImplAsm(El: TPasImplAsmStatement);
 procedure TPas2JSResolver.ResolveImplAsm(El: TPasImplAsmStatement);
@@ -4446,7 +4444,11 @@ begin
   else if ThisPas=El then
   else if ThisPas=El then
     Result:='this'
     Result:='this'
   else
   else
+    begin
     Result:=inherited GetLocalName(El);
     Result:=inherited GetLocalName(El);
+    if Result='this' then
+      Result:='';
+    end;
 end;
 end;
 
 
 function TFunctionContext.IndexOfLocalVar(const aName: string): integer;
 function TFunctionContext.IndexOfLocalVar(const aName: string): integer;
@@ -4636,17 +4638,23 @@ end;
 
 
 procedure TConvertContext.WriteStack;
 procedure TConvertContext.WriteStack;
 {AllowWriteln}
 {AllowWriteln}
+var
+  SelfCtx: TFunctionContext;
 
 
   procedure W(Index: integer; AContext: TConvertContext);
   procedure W(Index: integer; AContext: TConvertContext);
   begin
   begin
+    if AContext=SelfCtx then
+      writeln('  SelfContext:');
     AContext.DoWriteStack(Index);
     AContext.DoWriteStack(Index);
     if AContext.Parent<>nil then
     if AContext.Parent<>nil then
       W(Index+1,AContext.Parent);
       W(Index+1,AContext.Parent);
   end;
   end;
 
 
 begin
 begin
-  writeln('TConvertContext.WriteStack: ');
+  SelfCtx:=GetSelfContext;
+  writeln('TConvertContext.WriteStack: START');
   W(1,Self);
   W(1,Self);
+  writeln('TConvertContext.WriteStack: END');
 end;
 end;
 {AllowWriteln-}
 {AllowWriteln-}
 
 
@@ -10683,10 +10691,12 @@ begin
     Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FnName]);
     Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FnName]);
 
 
     // add parameter: owner. For top level class, the module is the owner.
     // add parameter: owner. For top level class, the module is the owner.
-    if (El.Parent<>nil) and (El.Parent.ClassType=TImplementationSection) then
-      OwnerName:=AContext.GetLocalName(El.Parent)
+    if (El.Parent=nil)
+        or ((El.Parent is TPasSection)
+          and (El.Parent.ClassType<>TImplementationSection)) then
+      OwnerName:=AContext.GetLocalName(El.GetModule)
     else
     else
-      OwnerName:=AContext.GetLocalName(El.GetModule);
+      OwnerName:=AContext.GetLocalName(El.Parent);
     if OwnerName='' then
     if OwnerName='' then
       OwnerName:='this';
       OwnerName:='this';
     Call.AddArg(CreatePrimitiveDotExpr(OwnerName,El));
     Call.AddArg(CreatePrimitiveDotExpr(OwnerName,El));
@@ -10782,10 +10792,7 @@ begin
           else if C=TPasConst then
           else if C=TPasConst then
             NewEl:=ConvertConst(TPasConst(P),aContext)
             NewEl:=ConvertConst(TPasConst(P),aContext)
           else if C=TPasProperty then
           else if C=TPasProperty then
-            begin
-            NewEl:=ConvertProperty(TPasProperty(P),AContext);
-            if NewEl=nil then continue;
-            end
+            NewEl:=ConvertProperty(TPasProperty(P),AContext)
           else if C.InheritsFrom(TPasType) then
           else if C.InheritsFrom(TPasType) then
             NewEl:=CreateTypeDecl(TPasType(P),aContext)
             NewEl:=CreateTypeDecl(TPasType(P),aContext)
           else if C.InheritsFrom(TPasProcedure) then
           else if C.InheritsFrom(TPasProcedure) then
@@ -10794,9 +10801,8 @@ begin
             continue
             continue
           else
           else
             RaiseNotSupported(P,FuncContext,20161221233338);
             RaiseNotSupported(P,FuncContext,20161221233338);
-          if NewEl=nil then
-            RaiseNotSupported(P,FuncContext,20170204223922);
-          AddToSourceElements(Src,NewEl);
+          if NewEl<>nil then
+            AddToSourceElements(Src,NewEl);
           end;
           end;
         end;
         end;
 
 
@@ -11810,35 +11816,40 @@ begin
       if ProcScope.ClassScope<>nil then
       if ProcScope.ClassScope<>nil then
         begin
         begin
         // method or class method
         // method or class method
-        FuncContext.ThisPas:=ProcScope.ClassScope.Element;
-        if bsObjectChecks in FuncContext.ScannerBoolSwitches then
+        if El.Parent is TProcedureBody then
           begin
           begin
-          // rtl.checkMethodCall(this,<class>)
-          Call:=CreateCallExpression(PosEl);
-          AddBodyStatement(Call,PosEl);
-          Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],
-                                          FBuiltInNames[pbifnCheckMethodCall]]);
-          Call.AddArg(CreatePrimitiveDotExpr('this',PosEl));
-          ClassPath:=CreateReferencePath(ProcScope.ClassScope.Element,AContext,rpkPathAndName);
-          Call.AddArg(CreatePrimitiveDotExpr(ClassPath,PosEl));
-          end;
-
-        if ImplProc.Body.Functions.Count>0 then
-          begin
-          // has nested procs -> add "var self = this;"
-          FuncContext.AddLocalVar(FBuiltInNames[pbivnSelf],FuncContext.ThisPas);
-          SelfSt:=CreateVarStatement(FBuiltInNames[pbivnSelf],
-                              CreatePrimitiveDotExpr('this',ImplProc),ImplProc);
-          AddBodyStatement(SelfSt,PosEl);
-          if ImplProcScope.SelfArg<>nil then
-            begin
-            // redirect Pascal-Self to JS-Self
-            FuncContext.AddLocalVar(FBuiltInNames[pbivnSelf],ImplProcScope.SelfArg);
-            end;
+          // nested sub procedure  ->  no 'this'
+          FuncContext.ThisPas:=nil;
           end
           end
         else
         else
           begin
           begin
-          if ImplProcScope.SelfArg<>nil then
+          FuncContext.ThisPas:=ProcScope.ClassScope.Element;
+          if bsObjectChecks in FuncContext.ScannerBoolSwitches then
+            begin
+            // rtl.checkMethodCall(this,<class>)
+            Call:=CreateCallExpression(PosEl);
+            AddBodyStatement(Call,PosEl);
+            Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],
+                                            FBuiltInNames[pbifnCheckMethodCall]]);
+            Call.AddArg(CreatePrimitiveDotExpr('this',PosEl));
+            ClassPath:=CreateReferencePath(ProcScope.ClassScope.Element,AContext,rpkPathAndName);
+            Call.AddArg(CreatePrimitiveDotExpr(ClassPath,PosEl));
+            end;
+
+          if ImplProc.Body.Functions.Count>0 then
+            begin
+            // has nested procs -> add "var self = this;"
+            FuncContext.AddLocalVar(FBuiltInNames[pbivnSelf],FuncContext.ThisPas);
+            SelfSt:=CreateVarStatement(FBuiltInNames[pbivnSelf],
+                                CreatePrimitiveDotExpr('this',ImplProc),ImplProc);
+            AddBodyStatement(SelfSt,PosEl);
+            if ImplProcScope.SelfArg<>nil then
+              begin
+              // redirect Pascal-Self to JS-Self
+              FuncContext.AddLocalVar(FBuiltInNames[pbivnSelf],ImplProcScope.SelfArg);
+              end;
+            end
+          else if ImplProcScope.SelfArg<>nil then
             begin
             begin
             // no nested procs ->  redirect Pascal-Self to JS-this
             // no nested procs ->  redirect Pascal-Self to JS-this
             FuncContext.AddLocalVar('this',ImplProcScope.SelfArg);
             FuncContext.AddLocalVar('this',ImplProcScope.SelfArg);
@@ -16267,12 +16278,41 @@ function TPasToJSConverter.CreateReferencePath(El: TPasElement;
     Result:=CreateReferencePath(AbsolResolved.IdentEl,AContext,Kind,Full,Ref);
     Result:=CreateReferencePath(AbsolResolved.IdentEl,AContext,Kind,Full,Ref);
   end;
   end;
 
 
+  function ImplToDecl(El: TPasElement): TPasElement;
+  var
+    ProcScope: TPasProcedureScope;
+  begin
+    Result:=El;
+    if El.CustomData is TPasProcedureScope then
+      begin
+      // proc: always use the declaration, not the body
+      ProcScope:=TPasProcedureScope(El.CustomData);
+      if ProcScope.DeclarationProc<>nil then
+        Result:=ProcScope.DeclarationProc;
+      end;
+  end;
+
+  function IsA(SrcType, DstType: TPasType): boolean;
+  begin
+    while SrcType<>nil do
+      begin
+      if SrcType=DstType then exit(true);
+      if SrcType.ClassType=TPasClassType then
+        SrcType:=TPas2JSClassScope(SrcType.CustomData).DirectAncestor
+      else if (SrcType.ClassType=TPasAliasType)
+          or (SrcType.ClassType=TPasTypeAliasType) then
+        SrcType:=TPasAliasType(SrcType).DestType
+      else
+        exit(false);
+      end;
+    Result:=false;
+  end;
+
 var
 var
   FoundModule: TPasModule;
   FoundModule: TPasModule;
   ParentEl: TPasElement;
   ParentEl: TPasElement;
   Dot: TDotContext;
   Dot: TDotContext;
   WithData: TPas2JSWithExprScope;
   WithData: TPas2JSWithExprScope;
-  ProcScope: TPasProcedureScope;
   ShortName: String;
   ShortName: String;
   SelfContext: TFunctionContext;
   SelfContext: TFunctionContext;
   ElClass: TClass;
   ElClass: TClass;
@@ -16346,7 +16386,7 @@ begin
     end
     end
   else if (ElClass=TPasClassType) and TPasClassType(El).IsExternal then
   else if (ElClass=TPasClassType) and TPasClassType(El).IsExternal then
     begin
     begin
-    // an external var -> use the literal
+    // an external class -> use the literal
     Result:=TPasClassType(El).ExternalName;
     Result:=TPasClassType(El).ExternalName;
     exit;
     exit;
     end
     end
@@ -16355,24 +16395,12 @@ begin
     // need full path
     // need full path
     if El.Parent=nil then
     if El.Parent=nil then
       RaiseNotSupported(El,AContext,20170201172141,GetObjName(El));
       RaiseNotSupported(El,AContext,20170201172141,GetObjName(El));
-    if (El.CustomData is TPasProcedureScope) then
-      begin
-      // proc: always use the declaration, not the body
-      ProcScope:=TPasProcedureScope(El.CustomData);
-      if ProcScope.DeclarationProc<>nil then
-        El:=ProcScope.DeclarationProc;
-      end;
+    El:=ImplToDecl(El);
 
 
     ParentEl:=El.Parent;
     ParentEl:=El.Parent;
     while ParentEl<>nil do
     while ParentEl<>nil do
       begin
       begin
-      if (ParentEl.CustomData is TPasProcedureScope) then
-        begin
-        // proc: always use the the declaration, not the body
-        ProcScope:=TPasProcedureScope(ParentEl.CustomData);
-        if ProcScope.DeclarationProc<>nil then
-          ParentEl:=ProcScope.DeclarationProc;
-        end;
+      ParentEl:=ImplToDecl(ParentEl);
 
 
       // check if there is a local var
       // check if there is a local var
       ShortName:=AContext.GetLocalName(ParentEl);
       ShortName:=AContext.GetLocalName(ParentEl);
@@ -16410,37 +16438,62 @@ begin
           Prepend(Result,ParentEl.Name)
           Prepend(Result,ParentEl.Name)
         else
         else
           begin
           begin
-          // Pascal and JS have similar scoping rules (we are not in a dotscope),
-          // so 'this' can be used.
+          // Not in a Pascal dotscope and accessing a class member.
+          // Possible results: this.v, module.path.path.v, this.path.v
+          //    In nested proc 'this' can have another name, e.g. '$Self'
           SelfContext:=AContext.GetSelfContext;
           SelfContext:=AContext.GetSelfContext;
           if ShortName<>'' then
           if ShortName<>'' then
-            Result:=ShortName
-          else if AContext.GetFunctionContext.ThisPas<>nil then
-            Result:='this'
-          else if SelfContext<>nil then
-            Result:=SelfContext.GetLocalName(SelfContext.ThisPas)
+            Prepend(Result,ShortName)
+          else if (El.Parent<>ParentEl) or (El is TPasType) then
+            Prepend(Result,ParentEl.Name)
+          else if (SelfContext<>nil)
+              and IsA(TPasType(SelfContext.ThisPas),TPasType(ParentEl)) then
+            begin
+            ShortName:=SelfContext.GetLocalName(SelfContext.ThisPas);
+            Prepend(Result,ShortName);
+            end
           else
           else
+            begin
+            // missing JS var for Self
+            {$IFDEF VerbosePas2JS}
+            writeln('TPasToJSConverter.CreateReferencePath missing JS var for Self: El=',El.FullName,':',El.ClassName,' CurParentEl=',ParentEl.FullName,':',ParentEl.ClassName,' AContext:');
+            AContext.WriteStack;
+            {$ENDIF}
             RaiseNotSupported(El,AContext,20180125004049);
             RaiseNotSupported(El,AContext,20180125004049);
-          if (SelfContext<>nil) and not IsClassFunction(SelfContext.PasElement) then
+            end;
+          if (El.Parent=ParentEl) and (SelfContext<>nil)
+              and not IsClassFunction(SelfContext.PasElement) then
             begin
             begin
             // inside a method -> Self is a class instance
             // inside a method -> Self is a class instance
             if El is TPasVariable then
             if El is TPasVariable then
               begin
               begin
               //writeln('TPasToJSConverter.CreateReferencePath class var ',GetObjName(El),' This=',GetObjName(This));
               //writeln('TPasToJSConverter.CreateReferencePath class var ',GetObjName(El),' This=',GetObjName(This));
+              // Note: reading a class var does not need accessing the class
+              //   For example: read v   ->  this.v
+              //                write v  ->  this.$class.v
               if (ClassVarModifiersType*TPasVariable(El).VarModifiers<>[])
               if (ClassVarModifiersType*TPasVariable(El).VarModifiers<>[])
                   and (AContext.Access=caAssign) then
                   and (AContext.Access=caAssign) then
                 begin
                 begin
-                  Append_GetClass(El); // writing a class var
+                Append_GetClass(El); // writing a class var
                 end;
                 end;
               end
               end
             else if IsClassFunction(El) then
             else if IsClassFunction(El) then
               Append_GetClass(El); // accessing a class function
               Append_GetClass(El); // accessing a class function
             end;
             end;
-          break;
+          if ShortName<>'' then
+            break;
           end;
           end;
         end
         end
       else if ParentEl.ClassType=TPasEnumType then
       else if ParentEl.ClassType=TPasEnumType then
-        Prepend(Result,ParentEl.Name);
+        begin
+        if (ShortName<>'') and not Full then
+          begin
+          Prepend(Result,ShortName);
+          break;
+          end
+        else
+          Prepend(Result,ParentEl.Name);
+        end;
       ParentEl:=ParentEl.Parent;
       ParentEl:=ParentEl.Parent;
       end;
       end;
     end;
     end;

+ 184 - 9
packages/pastojs/tests/tcmodules.pas

@@ -441,7 +441,9 @@ type
     Procedure TestClassOf_Const;
     Procedure TestClassOf_Const;
 
 
     // nested class
     // nested class
-    Procedure TestNestedClass_Fail;
+    Procedure TestNestedClass_Alias;
+    Procedure TestNestedClass_Record;
+    Procedure TestNestedClass_Class;
 
 
     // external class
     // external class
     Procedure TestExternalClass_Var;
     Procedure TestExternalClass_Var;
@@ -10523,12 +10525,12 @@ begin
     '      Self.SetSize(Self.GetSize() + 8);',
     '      Self.SetSize(Self.GetSize() + 8);',
     '    };',
     '    };',
     '    Sub();',
     '    Sub();',
-    '    this.Key = this.Key + 12;',
+    '    Self.Key = Self.Key + 12;',
     '    Self.Key = Self.Key + 13;',
     '    Self.Key = Self.Key + 13;',
-    '    this.$class.State = this.State + 14;',
+    '    Self.$class.State = Self.State + 14;',
     '    Self.$class.State = Self.State + 15;',
     '    Self.$class.State = Self.State + 15;',
     '    $mod.TObject.State = $mod.TObject.State + 16;',
     '    $mod.TObject.State = $mod.TObject.State + 16;',
-    '    this.SetSize(this.GetSize() + 17);',
+    '    Self.SetSize(Self.GetSize() + 17);',
     '    Self.SetSize(Self.GetSize() + 18);',
     '    Self.SetSize(Self.GetSize() + 18);',
     '  };',
     '  };',
     '});',
     '});',
@@ -11470,18 +11472,191 @@ begin
     '']));
     '']));
 end;
 end;
 
 
-procedure TTestModule.TestNestedClass_Fail;
+procedure TTestModule.TestNestedClass_Alias;
 begin
 begin
+  Converter.Options:=Converter.Options-[coNoTypeInfo];
   StartProgram(false);
   StartProgram(false);
   Add([
   Add([
   'type',
   'type',
   '  TObject = class',
   '  TObject = class',
-  '    type TNested = longint;',
+  '    type TNested = type longint;',
   '  end;',
   '  end;',
-  'begin']);
-  SetExpectedPasResolverError('not yet implemented: TNested:TPasAliasType [20170608232534] nested types',
-    nNotYetImplemented);
+  'type TAlias = type tobject.tnested;',
+  'var i: tobject.tnested = 3;',
+  'var j: TAlias = 4;',
+  'begin',
+  '  if typeinfo(TAlias)=nil then ;',
+  '  if typeinfo(tobject.tnested)=nil then ;',
+  '']);
   ConvertProgram;
   ConvertProgram;
+  CheckSource('TestNestedClass_Alias',
+    LinesToStr([ // statements
+    'rtl.createClass($mod, "TObject", null, function () {',
+    '  $mod.$rtti.$inherited("TObject.TNested", rtl.longint, {});',
+    '  this.$init = function () {',
+    '  };',
+    '  this.$final = function () {',
+    '  };',
+    '});',
+    '$mod.$rtti.$inherited("TAlias", $mod.$rtti["TObject.TNested"], {});',
+    'this.i = 3;',
+    'this.j = 4;',
+    '']),
+    LinesToStr([ // $mod.$main
+    'if ($mod.$rtti["TAlias"] === null) ;',
+    'if ($mod.$rtti["TObject.TNested"] === null) ;',
+    '']));
+end;
+
+procedure TTestModule.TestNestedClass_Record;
+begin
+  Converter.Options:=Converter.Options-[coNoTypeInfo];
+  StartProgram(false);
+  Add([
+  'type',
+  '  TObject = class',
+  '    type TPoint = record',
+  '       x,y: byte;',
+  '    end;',
+  '    procedure DoIt(t: TPoint);',
+  '  end;',
+  'procedure tobject.DoIt(t: TPoint);',
+  'var p: TPoint;',
+  'begin',
+  '  t.x:=t.y;',
+  '  p:=t;',
+  'end;',
+  'var',
+  '  p: tobject.tpoint = (x:2; y:4);',
+  '  o: TObject;',
+  'begin',
+  '  p:=p;',
+  '  o.doit(p);',
+  '']);
+  ConvertProgram;
+  CheckSource('TestNestedClass_Record',
+    LinesToStr([ // statements
+    'rtl.createClass($mod, "TObject", null, function () {',
+    '  this.TPoint = function (s) {',
+    '    if (s) {',
+    '      this.x = s.x;',
+    '      this.y = s.y;',
+    '    } else {',
+    '      this.x = 0;',
+    '      this.y = 0;',
+    '    };',
+    '    this.$equal = function (b) {',
+    '      return (this.x === b.x) && (this.y === b.y);',
+    '    };',
+    '  };',
+    '  $mod.$rtti.$Record("TObject.TPoint", {}).addFields("x", rtl.byte, "y", rtl.byte);',
+    '  this.$init = function () {',
+    '  };',
+    '  this.$final = function () {',
+    '  };',
+    '  this.DoIt = function (t) {',
+    '    var p = new this.TPoint();',
+    '    t.x = t.y;',
+    '    p = new this.TPoint(t);',
+    '  };',
+    '});',
+    'this.p = new $mod.TObject.TPoint({',
+    '  x: 2,',
+    '  y: 4',
+    '});',
+    'this.o = null;',
+    '']),
+    LinesToStr([ // $mod.$main
+    '$mod.p = new $mod.TObject.TPoint($mod.p);',
+    '$mod.o.DoIt(new $mod.TObject.TPoint($mod.p));',
+    '']));
+end;
+
+procedure TTestModule.TestNestedClass_Class;
+begin
+  Converter.Options:=Converter.Options-[coNoTypeInfo];
+  StartProgram(false);
+  Add([
+  'type',
+  '  TObject = class end;',
+  '  TBird = class',
+  '    type TLeg = class',
+  '      FId: longint;',
+  '      constructor Create;',
+  '      function Create(i: longint): TLeg;',
+  '    end;',
+  '    function DoIt(b: TBird): Tleg;',
+  '  end;',
+  'constructor tbird.tleg.create;',
+  'begin',
+  '  FId:=3;',
+  'end;',
+  'function tbird.tleg.Create(i: longint): TLeg;',
+  'begin',
+  '  Create;',
+  '  Result:=TLeg.Create;',
+  '  Result:=TBird.TLeg.Create;',
+  '  Result:=Create(3);',
+  '  FId:=i;',
+  'end;',
+  'function tbird.DoIt(b: tbird): tleg;',
+  'begin',
+  '  Result.Create;',
+  '  Result:=TLeg.Create;',
+  '  Result:=TBird.TLeg.Create;',
+  '  Result:=Result.Create(3);',
+  'end;',
+  'var',
+  '  b: Tbird.tleg;',
+  'begin',
+  '  b.Create;',
+  '  b:=TBird.TLeg.Create;',
+  '  b:=b.Create(3);',
+  '']);
+  ConvertProgram;
+  CheckSource('TestNestedClass_Class',
+    LinesToStr([ // statements
+    'rtl.createClass($mod, "TObject", null, function () {',
+    '  this.$init = function () {',
+    '  };',
+    '  this.$final = function () {',
+    '  };',
+    '});',
+    'rtl.createClass($mod, "TBird", $mod.TObject, function () {',
+    '  rtl.createClass(this, "TLeg", $mod.TObject, function () {',
+    '    this.$init = function () {',
+    '      $mod.TObject.$init.call(this);',
+    '      this.FId = 0;',
+    '    };',
+    '    this.Create = function () {',
+    '      this.FId = 3;',
+    '    };',
+    '    this.Create$1 = function (i) {',
+    '      var Result = null;',
+    '      this.Create();',
+    '      Result = $mod.TBird.TLeg.$create("Create");',
+    '      Result = $mod.TBird.TLeg.$create("Create");',
+    '      Result = this.Create$1(3);',
+    '      this.FId = i;',
+    '      return Result;',
+    '    };',
+    '  });',
+    '  this.DoIt = function (b) {',
+    '    var Result = null;',
+    '    Result.Create();',
+    '    Result = this.TLeg.$create("Create");',
+    '    Result = $mod.TBird.TLeg.$create("Create");',
+    '    Result = Result.Create$1(3);',
+    '    return Result;',
+    '  };',
+    '});',
+    'this.b = null;',
+    '']),
+    LinesToStr([ // $mod.$main
+    '$mod.b.Create();',
+    '$mod.b = $mod.TBird.TLeg.$create("Create");',
+    '$mod.b = $mod.b.Create$1(3);',
+    '']));
 end;
 end;
 
 
 procedure TTestModule.TestExternalClass_Var;
 procedure TTestModule.TestExternalClass_Var;

+ 1 - 2
utils/pas2js/docs/translation.html

@@ -1518,7 +1518,7 @@ function(){
     <li>Supported: constructor, destructor, private, protected, public,
     <li>Supported: constructor, destructor, private, protected, public,
       strict private, strict protected, class vars, class methods, external methods,
       strict private, strict protected, class vars, class methods, external methods,
       virtual, override, abstract, call inherited, assigned(), type cast,
       virtual, override, abstract, call inherited, assigned(), type cast,
-      overloads, reintroduce, sealed class</li>
+      overloads, reintroduce, sealed class, nested types.</li>
     <li>Not supported: class constructor/destructor</li>
     <li>Not supported: class constructor/destructor</li>
     <li>Property:
     <li>Property:
       <ul>
       <ul>
@@ -2863,7 +2863,6 @@ End.
     <li>Helpers for types, classes, records</li>
     <li>Helpers for types, classes, records</li>
     <li>Inline</li>
     <li>Inline</li>
     <li>Library</li>
     <li>Library</li>
-    <li>Nested classes</li>
     <li>Objects</li>
     <li>Objects</li>
     <li>Operator overloading</li>
     <li>Operator overloading</li>
     <li>Pointer arithmetic</li>
     <li>Pointer arithmetic</li>