Browse Source

pastojs: typeinfo for external classes

git-svn-id: trunk@43323 -
Mattias Gaertner 5 years ago
parent
commit
70ed2470dc

+ 99 - 20
packages/pastojs/src/fppas2js.pp

@@ -620,6 +620,7 @@ type
     pbifnRTTINewClassRef,// typeinfo of tkClassRef $ClassRef
     pbifnRTTINewClassRef,// typeinfo of tkClassRef $ClassRef
     pbifnRTTINewDynArray,// typeinfo of tkDynArray $DynArray
     pbifnRTTINewDynArray,// typeinfo of tkDynArray $DynArray
     pbifnRTTINewEnum,// typeinfo of tkEnumeration $Enum
     pbifnRTTINewEnum,// typeinfo of tkEnumeration $Enum
+    pbifnRTTINewExtClass,// typeinfo creator of tkExtClass $ExtClass
     pbifnRTTINewInt,// typeinfo of tkInt $Int
     pbifnRTTINewInt,// typeinfo of tkInt $Int
     pbifnRTTINewInterface,// typeinfo creator of tkInterface $Interface
     pbifnRTTINewInterface,// typeinfo creator of tkInterface $Interface
     pbifnRTTINewMethodVar,// typeinfo of tkMethod $MethodVar
     pbifnRTTINewMethodVar,// typeinfo of tkMethod $MethodVar
@@ -676,16 +677,18 @@ type
     pbivnRTTIInt_MinValue,
     pbivnRTTIInt_MinValue,
     pbivnRTTIInt_OrdType,
     pbivnRTTIInt_OrdType,
     pbivnRTTILocal, // $r
     pbivnRTTILocal, // $r
-    pbivnRTTIMemberAttributes,
+    pbivnRTTIMemberAttributes, // attr
     pbivnRTTIMethodKind, // tTypeInfoMethodVar has methodkind
     pbivnRTTIMethodKind, // tTypeInfoMethodVar has methodkind
-    pbivnRTTIPointer_RefType,
-    pbivnRTTIProcFlags,
-    pbivnRTTIProcVar_ProcSig,
-    pbivnRTTIPropDefault,
-    pbivnRTTIPropIndex,
-    pbivnRTTIPropStored,
-    pbivnRTTISet_CompType,
-    pbivnRTTITypeAttributes,
+    pbivnRTTIPointer_RefType, // reftype
+    pbivnRTTIProcFlags, // flags
+    pbivnRTTIProcVar_ProcSig, // procsig
+    pbivnRTTIPropDefault, // Default
+    pbivnRTTIPropIndex, // index
+    pbivnRTTIPropStored, // stored
+    pbivnRTTISet_CompType, // comptype
+    pbivnRTTITypeAttributes, // attr
+    pbivnRTTIExtClass_Ancestor, // ancestor
+    pbivnRTTIExtClass_JSClass, // jsclass
     pbivnSelf,
     pbivnSelf,
     pbivnTObjectDestroy,
     pbivnTObjectDestroy,
     pbivnWith,
     pbivnWith,
@@ -697,6 +700,7 @@ type
     pbitnTIClassRef,
     pbitnTIClassRef,
     pbitnTIDynArray,
     pbitnTIDynArray,
     pbitnTIEnum,
     pbitnTIEnum,
+    pbitnTIExtClass,
     pbitnTIHelper,
     pbitnTIHelper,
     pbitnTIInteger,
     pbitnTIInteger,
     pbitnTIInterface,
     pbitnTIInterface,
@@ -791,6 +795,7 @@ const
     '$ClassRef',
     '$ClassRef',
     '$DynArray',
     '$DynArray',
     '$Enum',
     '$Enum',
+    '$ExtClass',
     '$Int',
     '$Int',
     '$Interface',
     '$Interface',
     '$MethodVar',
     '$MethodVar',
@@ -856,6 +861,8 @@ const
     'stored', // pbivnRTTIPropStored
     'stored', // pbivnRTTIPropStored
     'comptype', // pbivnRTTISet_CompType
     'comptype', // pbivnRTTISet_CompType
     'attr', // pbivnRTTITypeAttributes
     'attr', // pbivnRTTITypeAttributes
+    'ancestor', // pbivnRTTIExtClass_Ancestor
+    'jsclass', // pbivnRTTIExtClass_JSClass
     '$Self', // pbivnSelf
     '$Self', // pbivnSelf
     'tObjectDestroy', // rtl.tObjectDestroy  pbivnTObjectDestroy
     'tObjectDestroy', // rtl.tObjectDestroy  pbivnTObjectDestroy
     '$with', // pbivnWith
     '$with', // pbivnWith
@@ -866,6 +873,7 @@ const
     'tTypeInfoClassRef', // pbitnTIClassRef
     'tTypeInfoClassRef', // pbitnTIClassRef
     'tTypeInfoDynArray', // pbitnTIDynArray
     'tTypeInfoDynArray', // pbitnTIDynArray
     'tTypeInfoEnum', // pbitnTIEnum
     'tTypeInfoEnum', // pbitnTIEnum
+    'tTypeInfoExtClass', // pbitnTIExtClass
     'tTypeInfoHelper', // pbitnTIHelper
     'tTypeInfoHelper', // pbitnTIHelper
     'tTypeInfoInteger', // pbitnTIInteger
     'tTypeInfoInteger', // pbitnTIInteger
     'tTypeInfoInterface', // pbitnTIInterface
     'tTypeInfoInterface', // pbitnTIInterface
@@ -2013,6 +2021,7 @@ type
     Function ConvertClassType(El: TPasClassType; AContext: TConvertContext): TJSElement; virtual;
     Function ConvertClassType(El: TPasClassType; AContext: TConvertContext): TJSElement; virtual;
     Function ConvertClassForwardType(El: TPasClassType; AContext: TConvertContext): TJSElement; virtual;
     Function ConvertClassForwardType(El: TPasClassType; AContext: TConvertContext): TJSElement; virtual;
     Function ConvertClassOfType(El: TPasClassOfType; AContext: TConvertContext): TJSElement; virtual;
     Function ConvertClassOfType(El: TPasClassOfType; AContext: TConvertContext): TJSElement; virtual;
+    Function ConvertExtClassType(El: TPasClassType; AContext: TConvertContext): TJSElement; virtual;
     Function ConvertEnumType(El: TPasEnumType; AContext: TConvertContext): TJSElement; virtual;
     Function ConvertEnumType(El: TPasEnumType; AContext: TConvertContext): TJSElement; virtual;
     Function ConvertSetType(El: TPasSetType; AContext: TConvertContext): TJSElement; virtual;
     Function ConvertSetType(El: TPasSetType; AContext: TConvertContext): TJSElement; virtual;
     Function ConvertRangeType(El: TPasRangeType; AContext: TConvertContext): TJSElement; virtual;
     Function ConvertRangeType(El: TPasRangeType; AContext: TConvertContext): TJSElement; virtual;
@@ -2288,7 +2297,7 @@ begin
     end;
     end;
   {$ENDIF}
   {$ENDIF}
   {$IFDEF VerbosePasResolver}
   {$IFDEF VerbosePasResolver}
-  if FindElevatedLocal(Item.Identifier)<>Item then
+  if Find(Item.Identifier)<>Item then
     raise Exception.Create('20160925183849');
     raise Exception.Create('20160925183849');
   {$ENDIF}
   {$ENDIF}
 end;
 end;
@@ -4914,7 +4923,11 @@ begin
       TIName:=Pas2JSBuiltInNames[pbitnTIRecord]
       TIName:=Pas2JSBuiltInNames[pbitnTIRecord]
     else if C=TPasClassType then
     else if C=TPasClassType then
       case TPasClassType(TypeEl).ObjKind of
       case TPasClassType(TypeEl).ObjKind of
-      okClass: TIName:=Pas2JSBuiltInNames[pbitnTIClass];
+      okClass:
+        if TPasClassType(TypeEl).IsExternal then
+          TIName:=Pas2JSBuiltInNames[pbitnTIExtClass]
+        else
+          TIName:=Pas2JSBuiltInNames[pbitnTIClass];
       okInterface: TIName:=Pas2JSBuiltInNames[pbitnTIInterface];
       okInterface: TIName:=Pas2JSBuiltInNames[pbitnTIInterface];
       okClassHelper,okRecordHelper,okTypeHelper: TIName:=Pas2JSBuiltInNames[pbitnTIHelper];
       okClassHelper,okRecordHelper,okTypeHelper: TIName:=Pas2JSBuiltInNames[pbitnTIHelper];
       else
       else
@@ -4950,7 +4963,12 @@ begin
           if not (ConEl is TPasType) then
           if not (ConEl is TPasType) then
             RaiseNotYetImplemented(20191018180031,ConEl,GetObjPath(Param));
             RaiseNotYetImplemented(20191018180031,ConEl,GetObjPath(Param));
           if ConEl is TPasClassType then
           if ConEl is TPasClassType then
-            TIName:=Pas2JSBuiltInNames[pbitnTIClass]
+            begin
+            if TPasClassType(ConEl).IsExternal then
+              TIName:=Pas2JSBuiltInNames[pbitnTIExtClass]
+            else
+              TIName:=Pas2JSBuiltInNames[pbitnTIClass];
+            end
           else
           else
             RaiseNotYetImplemented(20191018180131,ConEl,GetObjPath(Param));
             RaiseNotYetImplemented(20191018180131,ConEl,GetObjPath(Param));
         end;
         end;
@@ -5859,8 +5877,6 @@ function TPas2JSResolver.HasTypeInfo(El: TPasType): boolean;
 begin
 begin
   Result:=inherited HasTypeInfo(El);
   Result:=inherited HasTypeInfo(El);
   if not Result then exit;
   if not Result then exit;
-  if (El.ClassType=TPasClassType) and TPasClassType(El).IsExternal then
-    exit(false);
   if El.Parent is TProcedureBody then
   if El.Parent is TProcedureBody then
     Result:=false;
     Result:=false;
 end;
 end;
@@ -13592,14 +13608,14 @@ begin
     RaiseNotSupported(El,AContext,20170927183645);
     RaiseNotSupported(El,AContext,20170927183645);
   if El.Parent is TProcedureBody then
   if El.Parent is TProcedureBody then
     RaiseNotSupported(El,AContext,20181231004355);
     RaiseNotSupported(El,AContext,20181231004355);
+  if El.IsExternal then
+    exit(ConvertExtClassType(El,AContext));
   if El.IsForward then
   if El.IsForward then
     begin
     begin
     Result:=ConvertClassForwardType(El,AContext);
     Result:=ConvertClassForwardType(El,AContext);
     exit;
     exit;
     end;
     end;
 
 
-  if El.IsExternal then exit;
-
   if El.CustomData is TPas2JSClassScope then
   if El.CustomData is TPas2JSClassScope then
     begin
     begin
     Scope:=TPas2JSClassScope(El.CustomData);
     Scope:=TPas2JSClassScope(El.CustomData);
@@ -13906,6 +13922,59 @@ begin
   end;
   end;
 end;
 end;
 
 
+function TPasToJSConverter.ConvertExtClassType(El: TPasClassType;
+  AContext: TConvertContext): TJSElement;
+//   module.$rtti.$ExtClass("TJSObject",{
+//     ancestor: ancestortypeinfo,
+//     jsclass: "Object"
+//   });
+var
+  TIObj: TJSObjectLiteral;
+  Call: TJSCallExpression;
+  TIProp: TJSObjectLiteralElement;
+  ClassScope: TPas2JSClassScope;
+  AncestorType: TPasClassType;
+begin
+  Result:=nil;
+  if not El.IsExternal then
+    RaiseNotSupported(El,AContext,20191027183236);
+
+  if not HasTypeInfo(El,AContext) then
+    exit;
+  // create typeinfo
+  if not (AContext is TFunctionContext) then
+    RaiseNotSupported(El,AContext,20191027182023,'typeinfo');
+  if El.Parent is TProcedureBody then
+    RaiseNotSupported(El,AContext,20191027182019);
+
+  ClassScope:=El.CustomData as TPas2JSClassScope;
+  if ClassScope.AncestorScope<>nil then
+    AncestorType:=ClassScope.AncestorScope.Element as TPasClassType
+  else
+    AncestorType:=nil;
+
+  Call:=nil;
+  try
+    // module.$rtti.$ExtClass("TMyClass",{...});
+    Call:=CreateRTTINewType(El,GetBIName(pbifnRTTINewExtClass),false,AContext,TIObj);
+    if AncestorType<>nil then
+      begin
+      // add  ancestor: ancestortypeinfo
+      TIProp:=TIObj.Elements.AddElement;
+      TIProp.Name:=TJSString(GetBIName(pbivnRTTIExtClass_Ancestor));
+      TIProp.Expr:=CreateTypeInfoRef(AncestorType,AContext,El);
+      end;
+    // add  jsclass: "extname"
+    TIProp:=TIObj.Elements.AddElement;
+    TIProp.Name:=TJSString(GetBIName(pbivnRTTIExtClass_JSClass));
+    TIProp.Expr:=CreateLiteralString(El,TPasClassType(El).ExternalName);
+    Result:=Call;
+  finally
+    if Result=nil then
+      Call.Free;
+  end;
+end;
+
 function TPasToJSConverter.ConvertEnumType(El: TPasEnumType;
 function TPasToJSConverter.ConvertEnumType(El: TPasEnumType;
   AContext: TConvertContext): TJSElement;
   AContext: TConvertContext): TJSElement;
 // TMyEnum = (red, green)
 // TMyEnum = (red, green)
@@ -13916,7 +13985,7 @@ function TPasToJSConverter.ConvertEnumType(El: TPasEnumType;
 //     "0":"green",
 //     "0":"green",
 //     "green":0,
 //     "green":0,
 //   };
 //   };
-//   module.$rtti.$TIEnum("TMyEnum",{
+//   module.$rtti.$Enum("TMyEnum",{
 //     enumtype: this.TMyEnum,
 //     enumtype: this.TMyEnum,
 //     minvalue: 0,
 //     minvalue: 0,
 //     maxvalue: 1
 //     maxvalue: 1
@@ -21866,15 +21935,25 @@ var
   end;
   end;
 
 
   function IsA(SrcType, DstType: TPasType): boolean;
   function IsA(SrcType, DstType: TPasType): boolean;
+  var
+    C: TClass;
   begin
   begin
     while SrcType<>nil do
     while SrcType<>nil do
       begin
       begin
       if SrcType=DstType then exit(true);
       if SrcType=DstType then exit(true);
-      if SrcType.ClassType=TPasClassType then
+      C:=SrcType.ClassType;
+      if C=TPasClassType then
         SrcType:=TPas2JSClassScope(SrcType.CustomData).DirectAncestor
         SrcType:=TPas2JSClassScope(SrcType.CustomData).DirectAncestor
-      else if (SrcType.ClassType=TPasAliasType)
-          or (SrcType.ClassType=TPasTypeAliasType) then
+      else if (C=TPasAliasType)
+          or (C=TPasTypeAliasType) then
         SrcType:=TPasAliasType(SrcType).DestType
         SrcType:=TPasAliasType(SrcType).DestType
+      else if C=TPasSpecializeType then
+        begin
+        if SrcType.CustomData is TPasSpecializeTypeData then
+          SrcType:=TPasSpecializeTypeData(SrcType.CustomData).SpecializedType
+        else
+          RaiseInconsistency(20191027172642,SrcType);
+        end
       else
       else
         exit(false);
         exit(false);
       end;
       end;

+ 58 - 7
packages/pastojs/tests/tcgenerics.pas

@@ -24,6 +24,7 @@ type
     Procedure TestGen_ClassEmpty;
     Procedure TestGen_ClassEmpty;
     Procedure TestGen_Class_EmptyMethod;
     Procedure TestGen_Class_EmptyMethod;
     Procedure TestGen_Class_TList;
     Procedure TestGen_Class_TList;
+    Procedure TestGen_Class_TCustomList;
     Procedure TestGen_ClassAncestor;
     Procedure TestGen_ClassAncestor;
     Procedure TestGen_Class_TypeInfo;
     Procedure TestGen_Class_TypeInfo;
     Procedure TestGen_Class_TypeOverload; // ToDo TBird, TBird<T>, TBird<S,T>
     Procedure TestGen_Class_TypeOverload; // ToDo TBird, TBird<T>, TBird<S,T>
@@ -289,6 +290,62 @@ begin
     '']));
     '']));
 end;
 end;
 
 
+procedure TTestGenerics.TestGen_Class_TCustomList;
+begin
+  StartProgram(false);
+  Add([
+  '{$mode delphi}',
+  'type',
+  '  TObject = class end;',
+  '  TCustomList<T> = class',
+  '  public',
+  '    function PrepareAddingItem: word; virtual;',
+  '  end;',
+  '  TList<T> = class(TCustomList<T>)',
+  '  public',
+  '    function Add: word;',
+  '  end;',
+  '  TWordList = TList<word>;',
+  'function TCustomList<T>.PrepareAddingItem: word;',
+  'begin',
+  'end;',
+  'function TList<T>.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;
 procedure TTestGenerics.TestGen_ClassAncestor;
 begin
 begin
   StartProgram(false);
   StartProgram(false);
@@ -1030,15 +1087,9 @@ end;
 procedure TTestGenerics.TestGenProc_TypeInfo;
 procedure TTestGenerics.TestGenProc_TypeInfo;
 begin
 begin
   Converter.Options:=Converter.Options-[coNoTypeInfo];
   Converter.Options:=Converter.Options-[coNoTypeInfo];
-  StartProgram(false);
+  StartProgram(true,[supTypeInfo]);
   Add([
   Add([
-  '{$modeswitch externalclass}',
   '{$modeswitch implicitfunctionspecialization}',
   '{$modeswitch implicitfunctionspecialization}',
-  'type',
-  '  TTypeInfo = class external name ''rtl.tTypeInfo''',
-  '  end;',
-  '  TTypeInfoInteger = class external name ''rtl.tTypeInfoInteger''(TTypeInfo)',
-  '  end;',
   'generic procedure Run<S>(a: S);',
   'generic procedure Run<S>(a: S);',
   'var',
   'var',
   '  p: TTypeInfo;',
   '  p: TTypeInfo;',

+ 69 - 40
packages/pastojs/tests/tcmodules.pas

@@ -51,7 +51,8 @@ type
 
 
   TSystemUnitPart = (
   TSystemUnitPart = (
     supTObject,
     supTObject,
-    supTVarRec
+    supTVarRec,
+    supTypeInfo
     );
     );
   TSystemUnitParts = set of TSystemUnitPart;
   TSystemUnitParts = set of TSystemUnitPart;
 
 
@@ -816,6 +817,7 @@ type
     Procedure TestRTTI_Interface_Corba;
     Procedure TestRTTI_Interface_Corba;
     Procedure TestRTTI_Interface_COM;
     Procedure TestRTTI_Interface_COM;
     Procedure TestRTTI_ClassHelper;
     Procedure TestRTTI_ClassHelper;
+    Procedure TestRTTI_ExternalClass;
 
 
     // Resourcestring
     // Resourcestring
     Procedure TestResourcestringProgram;
     Procedure TestResourcestringProgram;
@@ -1557,7 +1559,7 @@ var
 begin
 begin
   Intf:=TStringList.Create;
   Intf:=TStringList.Create;
   // interface
   // interface
-  if supTVarRec in Parts then
+  if [supTVarRec,supTypeInfo]*Parts<>[] then
     Intf.Add('{$modeswitch externalclass}');
     Intf.Add('{$modeswitch externalclass}');
   Intf.Add('type');
   Intf.Add('type');
   Intf.Add('  integer=longint;');
   Intf.Add('  integer=longint;');
@@ -1603,6 +1605,28 @@ begin
     '  TVarRecArray = array of TVarRec;',
     '  TVarRecArray = array of TVarRec;',
     'function VarRecs: TVarRecArray; varargs;',
     'function VarRecs: TVarRecArray; varargs;',
     '']);
     '']);
+  if supTypeInfo in Parts then
+    begin
+    Intf.AddStrings([
+    'type',
+    '  TTypeInfo = class external name ''rtl.tTypeInfo'' end;',
+    '  TTypeInfoInteger = class external name ''rtl.tTypeInfoInteger''(TTypeInfo)',
+    '  end;',
+    '  TTypeInfoEnum = class external name ''rtl.tTypeInfoEnum''(TTypeInfoInteger) end;',
+    '  TTypeInfoSet = class external name ''rtl.tTypeInfoSet''(TTypeInfo) end;',
+    '  TTypeInfoStaticArray = class external name ''rtl.tTypeInfoStaticArray''(TTypeInfo) end;',
+    '  TTypeInfoDynArray = class external name ''rtl.tTypeInfoDynArray''(TTypeInfo) end;',
+    '  TTypeInfoProcVar = class external name ''rtl.tTypeInfoProcVar''(TTypeInfo) end;',
+    '  TTypeInfoMethodVar = class external name ''rtl.tTypeInfoMethodVar''(TTypeInfoProcVar) end;',
+    '  TTypeInfoClass = class external name ''rtl.tTypeInfoClass''(TTypeInfo) end;',
+    '  TTypeInfoClassRef = class external name ''rtl.tTypeInfoClassRef''(TTypeInfo) end;',
+    '  TTypeInfoExtClass = class external name ''rtl.tTypeInfoExtClass''(TTypeInfo) end;',
+    '  TTypeInfoRecord = class external name ''rtl.tTypeInfoRecord''(TTypeInfo) end;',
+    '  TTypeInfoPointer = class external name ''rtl.tTypeInfoPointer''(TTypeInfo) end;',
+    '  TTypeInfoHelper = class external name ''rtl.tTypeInfoHelper''(TTypeInfo) end;',
+    '  TTypeInfoInterface = class external name ''rtl.tTypeInfoInterface''(TTypeInfo) end;',
+    '']);
+    end;
   Intf.Add('var');
   Intf.Add('var');
   Intf.Add('  ExitCode: Longint = 0;');
   Intf.Add('  ExitCode: Longint = 0;');
 
 
@@ -27286,14 +27310,10 @@ end;
 procedure TTestModule.TestRTTI_IntRange;
 procedure TTestModule.TestRTTI_IntRange;
 begin
 begin
   Converter.Options:=Converter.Options-[coNoTypeInfo];
   Converter.Options:=Converter.Options-[coNoTypeInfo];
-  StartProgram(false);
+  StartProgram(true,[supTypeInfo]);
   Add([
   Add([
   '{$modeswitch externalclass}',
   '{$modeswitch externalclass}',
   'type',
   'type',
-  '  TTypeInfo = class external name ''rtl.tTypeInfo''',
-  '  end;',
-  '  TTypeInfoInteger = class external name ''rtl.tTypeInfoInteger''(TTypeInfo)',
-  '  end;',
   '  TGraphicsColor = -$7FFFFFFF-1..$7FFFFFFF;',
   '  TGraphicsColor = -$7FFFFFFF-1..$7FFFFFFF;',
   '  TColor = type TGraphicsColor;',
   '  TColor = type TGraphicsColor;',
   'var',
   'var',
@@ -27322,12 +27342,10 @@ end;
 procedure TTestModule.TestRTTI_Double;
 procedure TTestModule.TestRTTI_Double;
 begin
 begin
   Converter.Options:=Converter.Options-[coNoTypeInfo];
   Converter.Options:=Converter.Options-[coNoTypeInfo];
-  StartProgram(false);
+  StartProgram(true,[supTypeInfo]);
   Add([
   Add([
   '{$modeswitch externalclass}',
   '{$modeswitch externalclass}',
   'type',
   'type',
-  '  TTypeInfo = class external name ''rtl.tTypeInfo''',
-  '  end;',
   '  TFloat = type double;',
   '  TFloat = type double;',
   'var',
   'var',
   '  p: TTypeInfo;',
   '  p: TTypeInfo;',
@@ -29032,16 +29050,12 @@ end;
 procedure TTestModule.TestRTTI_TypeInfo_ExtTypeInfoClasses1;
 procedure TTestModule.TestRTTI_TypeInfo_ExtTypeInfoClasses1;
 begin
 begin
   Converter.Options:=Converter.Options-[coNoTypeInfo];
   Converter.Options:=Converter.Options-[coNoTypeInfo];
-  StartProgram(false);
+  StartProgram(true,[supTypeInfo]);
   Add([
   Add([
   '{$modeswitch externalclass}',
   '{$modeswitch externalclass}',
   'type',
   'type',
-  '  TTypeInfo = class external name ''rtl.tTypeInfo'' end;',
-  '  TTypeInfoInteger = class external name ''rtl.tTypeInfoInteger''(TTypeInfo) end;',
   '  TFlag = (up,down);',
   '  TFlag = (up,down);',
-  '  TTypeInfoEnum = class external name ''rtl.tTypeInfoEnum''(TTypeInfoInteger) end;',
   '  TFlags = set of TFlag;',
   '  TFlags = set of TFlag;',
-  '  TTypeInfoSet = class external name ''rtl.tTypeInfoSet''(TTypeInfo) end;',
   'var',
   'var',
   '  ti: TTypeInfo;',
   '  ti: TTypeInfo;',
   '  tiInt: TTypeInfoInteger;',
   '  tiInt: TTypeInfoInteger;',
@@ -29104,18 +29118,13 @@ end;
 procedure TTestModule.TestRTTI_TypeInfo_ExtTypeInfoClasses2;
 procedure TTestModule.TestRTTI_TypeInfo_ExtTypeInfoClasses2;
 begin
 begin
   Converter.Options:=Converter.Options-[coNoTypeInfo];
   Converter.Options:=Converter.Options-[coNoTypeInfo];
-  StartProgram(false);
+  StartProgram(true,[supTypeInfo]);
   Add('{$modeswitch externalclass}');
   Add('{$modeswitch externalclass}');
   Add('type');
   Add('type');
-  Add('  TTypeInfo = class external name ''rtl.tTypeInfo'' end;');
   Add('  TStaticArr = array[boolean] of string;');
   Add('  TStaticArr = array[boolean] of string;');
-  Add('  TTypeInfoStaticArray = class external name ''rtl.tTypeInfoStaticArray''(TTypeInfo) end;');
   Add('  TDynArr = array of string;');
   Add('  TDynArr = array of string;');
-  Add('  TTypeInfoDynArray = class external name ''rtl.tTypeInfoDynArray''(TTypeInfo) end;');
   Add('  TProc = procedure;');
   Add('  TProc = procedure;');
-  Add('  TTypeInfoProcVar = class external name ''rtl.tTypeInfoProcVar''(TTypeInfo) end;');
   Add('  TMethod = procedure of object;');
   Add('  TMethod = procedure of object;');
-  Add('  TTypeInfoMethodVar = class external name ''rtl.tTypeInfoMethodVar''(TTypeInfoProcVar) end;');
   Add('var');
   Add('var');
   Add('  StaticArray: TStaticArr;');
   Add('  StaticArray: TStaticArr;');
   Add('  tiStaticArray: TTypeInfoStaticArray;');
   Add('  tiStaticArray: TTypeInfoStaticArray;');
@@ -29175,18 +29184,13 @@ end;
 procedure TTestModule.TestRTTI_TypeInfo_ExtTypeInfoClasses3;
 procedure TTestModule.TestRTTI_TypeInfo_ExtTypeInfoClasses3;
 begin
 begin
   Converter.Options:=Converter.Options-[coNoTypeInfo];
   Converter.Options:=Converter.Options-[coNoTypeInfo];
-  StartProgram(false);
+  StartProgram(true,[supTypeInfo]);
   Add('{$modeswitch externalclass}');
   Add('{$modeswitch externalclass}');
   Add('type');
   Add('type');
-  Add('  TTypeInfo = class external name ''rtl.tTypeInfo'' end;');
   Add('  TRec = record end;');
   Add('  TRec = record end;');
-  Add('  TTypeInfoRecord = class external name ''rtl.tTypeInfoRecord''(TTypeInfo) end;');
   // ToDo: ^PRec
   // ToDo: ^PRec
   Add('  TObject = class end;');
   Add('  TObject = class end;');
-  Add('  TTypeInfoClass = class external name ''rtl.tTypeInfoClass''(TTypeInfo) end;');
   Add('  TClass = class of tobject;');
   Add('  TClass = class of tobject;');
-  Add('  TTypeInfoClassRef = class external name ''rtl.tTypeInfoClassRef''(TTypeInfo) end;');
-  Add('  TTypeInfoPointer = class external name ''rtl.tTypeInfoPointer''(TTypeInfo) end;');
   Add('var');
   Add('var');
   Add('  Rec: trec;');
   Add('  Rec: trec;');
   Add('  tiRecord: ttypeinforecord;');
   Add('  tiRecord: ttypeinforecord;');
@@ -29245,7 +29249,7 @@ end;
 procedure TTestModule.TestRTTI_TypeInfo_FunctionClassType;
 procedure TTestModule.TestRTTI_TypeInfo_FunctionClassType;
 begin
 begin
   Converter.Options:=Converter.Options-[coNoTypeInfo];
   Converter.Options:=Converter.Options-[coNoTypeInfo];
-  StartProgram(false);
+  StartProgram(true,[supTypeInfo]);
   Add([
   Add([
   '{$modeswitch externalclass}',
   '{$modeswitch externalclass}',
   'type',
   'type',
@@ -29254,8 +29258,6 @@ begin
   '    function MyClass: TClass;',
   '    function MyClass: TClass;',
   '    class function ClassType: TClass;',
   '    class function ClassType: TClass;',
   '  end;',
   '  end;',
-  '  TTypeInfo = class external name ''rtl.tTypeInfo'' end;',
-  '  TTypeInfoClass = class external name ''rtl.tTypeInfoClass''(TTypeInfo) end;',
   'function TObject.MyClass: TClass;',
   'function TObject.MyClass: TClass;',
   'var t: TTypeInfoClass;',
   'var t: TTypeInfoClass;',
   'begin',
   'begin',
@@ -29398,7 +29400,7 @@ end;
 procedure TTestModule.TestRTTI_Interface_Corba;
 procedure TTestModule.TestRTTI_Interface_Corba;
 begin
 begin
   Converter.Options:=Converter.Options-[coNoTypeInfo];
   Converter.Options:=Converter.Options-[coNoTypeInfo];
-  StartProgram(false);
+  StartProgram(true,[supTypeInfo]);
   Add([
   Add([
   '{$interfaces corba}',
   '{$interfaces corba}',
   '{$modeswitch externalclass}',
   '{$modeswitch externalclass}',
@@ -29410,8 +29412,6 @@ begin
   '    procedure SetItem(Value: longint);',
   '    procedure SetItem(Value: longint);',
   '    property Item: longint read GetItem write SetItem;',
   '    property Item: longint read GetItem write SetItem;',
   '  end;',
   '  end;',
-  '  TTypeInfo = class external name ''rtl.tTypeInfo'' end;',
-  '  TTypeInfoInterface = class external name ''rtl.tTypeInfoInterface''(TTypeInfo) end;',
   'procedure DoIt(t: TTypeInfoInterface); begin end;',
   'procedure DoIt(t: TTypeInfoInterface); begin end;',
   'var',
   'var',
   '  i: IBird;',
   '  i: IBird;',
@@ -29463,7 +29463,7 @@ end;
 procedure TTestModule.TestRTTI_Interface_COM;
 procedure TTestModule.TestRTTI_Interface_COM;
 begin
 begin
   Converter.Options:=Converter.Options-[coNoTypeInfo];
   Converter.Options:=Converter.Options-[coNoTypeInfo];
-  StartProgram(false);
+  StartProgram(true,[supTypeInfo]);
   Add([
   Add([
   '{$interfaces com}',
   '{$interfaces com}',
   '{$modeswitch externalclass}',
   '{$modeswitch externalclass}',
@@ -29480,8 +29480,6 @@ begin
   '    procedure SetItem(Value: longint);',
   '    procedure SetItem(Value: longint);',
   '    property Item: longint read GetItem write SetItem;',
   '    property Item: longint read GetItem write SetItem;',
   '  end;',
   '  end;',
-  '  TTypeInfo = class external name ''rtl.tTypeInfo'' end;',
-  '  TTypeInfoInterface = class external name ''rtl.tTypeInfoInterface''(TTypeInfo) end;',
   'var',
   'var',
   '  i: IBird;',
   '  i: IBird;',
   '  t: TTypeInfoInterface;',
   '  t: TTypeInfoInterface;',
@@ -29540,7 +29538,7 @@ end;
 procedure TTestModule.TestRTTI_ClassHelper;
 procedure TTestModule.TestRTTI_ClassHelper;
 begin
 begin
   Converter.Options:=Converter.Options-[coNoTypeInfo];
   Converter.Options:=Converter.Options-[coNoTypeInfo];
-  StartProgram(false);
+  StartProgram(true,[supTypeInfo]);
   Add([
   Add([
   '{$interfaces com}',
   '{$interfaces com}',
   '{$modeswitch externalclass}',
   '{$modeswitch externalclass}',
@@ -29552,8 +29550,6 @@ begin
   '    function GetItem: longint;',
   '    function GetItem: longint;',
   '    property Item: longint read GetItem;',
   '    property Item: longint read GetItem;',
   '  end;',
   '  end;',
-  '  TTypeInfo = class external name ''rtl.tTypeInfo'' end;',
-  '  TTypeInfoHelper = class external name ''rtl.tTypeInfoHelper''(TTypeInfo) end;',
   'function THelper.GetItem: longint;',
   'function THelper.GetItem: longint;',
   'begin',
   'begin',
   'end;',
   'end;',
@@ -29587,6 +29583,40 @@ begin
     '']));
     '']));
 end;
 end;
 
 
+procedure TTestModule.TestRTTI_ExternalClass;
+begin
+  Converter.Options:=Converter.Options-[coNoTypeInfo];
+  StartProgram(true,[supTypeInfo]);
+  Add([
+  '{$modeswitch externalclass}',
+  'type',
+  '  TJSObject = class external name ''Object''',
+  '  end;',
+  '  TJSArray = class external name ''Array'' (TJSObject)',
+  '  end;',
+  'var',
+  '  p: Pointer;',
+  '  tc: TTypeInfoExtClass;',
+  'begin',
+  '  p:=typeinfo(TJSArray);']);
+  ConvertProgram;
+  CheckSource('TestRTTI_ExternalClass',
+    LinesToStr([ // statements
+    '$mod.$rtti.$ExtClass("TJSObject", {',
+    '  jsclass: "Object"',
+    '});',
+    '$mod.$rtti.$ExtClass("TJSArray", {',
+    '  ancestor: $mod.$rtti["TJSObject"],',
+    '  jsclass: "Array"',
+    '});',
+    'this.p = null;',
+    'this.tc = null;',
+    '']),
+    LinesToStr([ // $mod.$main
+    '$mod.p = $mod.$rtti["TJSArray"];',
+    '']));
+end;
+
 procedure TTestModule.TestResourcestringProgram;
 procedure TTestModule.TestResourcestringProgram;
 begin
 begin
   StartProgram(false);
   StartProgram(false);
@@ -29880,7 +29910,6 @@ begin
   'constructor THelper.Create(Id: word); begin end;',
   'constructor THelper.Create(Id: word); begin end;',
   'begin',
   'begin',
   '  if typeinfo(TMyInt)=nil then ;']);
   '  if typeinfo(TMyInt)=nil then ;']);
-  //SetExpectedConverterError('aaa',123);
   ConvertProgram;
   ConvertProgram;
 end;
 end;
 
 

+ 12 - 9
utils/pas2js/dist/rtl.js

@@ -7,7 +7,7 @@ var rtl = {
   quiet: false,
   quiet: false,
   debug_load_units: false,
   debug_load_units: false,
   debug_rtti: false,
   debug_rtti: false,
-  
+
   $res : {},
   $res : {},
 
 
   debug: function(){
   debug: function(){
@@ -1316,6 +1316,7 @@ var rtl = {
     newBaseTI("tTypeInfoClassRef",14 /* tkClassRef */);
     newBaseTI("tTypeInfoClassRef",14 /* tkClassRef */);
     newBaseTI("tTypeInfoInterface",18 /* tkInterface */,rtl.tTypeInfoStruct);
     newBaseTI("tTypeInfoInterface",18 /* tkInterface */,rtl.tTypeInfoStruct);
     newBaseTI("tTypeInfoHelper",19 /* tkHelper */,rtl.tTypeInfoStruct);
     newBaseTI("tTypeInfoHelper",19 /* tkHelper */,rtl.tTypeInfoStruct);
+    newBaseTI("tTypeInfoExtClass",20 /* tkExtClass */,rtl.tTypeInfoClass);
   },
   },
 
 
   tSectionRTTI: {
   tSectionRTTI: {
@@ -1366,7 +1367,8 @@ var rtl = {
     $ClassRef: function(name,o){ return this.$inherited(name,rtl.tTypeInfoClassRef,o); },
     $ClassRef: function(name,o){ return this.$inherited(name,rtl.tTypeInfoClassRef,o); },
     $Pointer: function(name,o){ return this.$inherited(name,rtl.tTypeInfoPointer,o); },
     $Pointer: function(name,o){ return this.$inherited(name,rtl.tTypeInfoPointer,o); },
     $Interface: function(name,o){ return this.$Scope(name,rtl.tTypeInfoInterface,o); },
     $Interface: function(name,o){ return this.$Scope(name,rtl.tTypeInfoInterface,o); },
-    $Helper: function(name,o){ return this.$Scope(name,rtl.tTypeInfoHelper,o); }
+    $Helper: function(name,o){ return this.$Scope(name,rtl.tTypeInfoHelper,o); },
+    $ExtClass: function(name,o){ return this.$Scope(name,rtl.tTypeInfoExtClass,o); }
   },
   },
 
 
   newTIParam: function(param){
   newTIParam: function(param){
@@ -1396,21 +1398,22 @@ var rtl = {
     };
     };
     return s;
     return s;
   },
   },
-  
-  addResource : function (aRes) {
+
+  addResource: function(aRes){
     rtl.$res[aRes.name]=aRes;
     rtl.$res[aRes.name]=aRes;
   },
   },
 
 
-  getResource : function (aName) {
+  getResource: function(aName){
     var res = rtl.$res[aName];
     var res = rtl.$res[aName];
     if (res !== undefined) {
     if (res !== undefined) {
       return res;
       return res;
-    } else  {
+    } else {
       return null;
       return null;
-    }  
+    }
   },
   },
-  
-  getResourceList : function () {
+
+  getResourceList: function(){
     return Object.keys(rtl.$res);
     return Object.keys(rtl.$res);
   }
   }
 }
 }
+