Browse Source

fcl-passrc: resolver: fixed find ancestor property

git-svn-id: trunk@41087 -
Mattias Gaertner 6 years ago
parent
commit
70fa288fc4

+ 33 - 1
packages/fcl-passrc/src/pasresolver.pp

@@ -939,6 +939,8 @@ type
     destructor Destroy; override;
     destructor Destroy; override;
     function GetFirstNonHelperScope: TPasIdentifierScope;
     function GetFirstNonHelperScope: TPasIdentifierScope;
     class function IsStoredInElement: boolean; override;
     class function IsStoredInElement: boolean; override;
+    function FindAncestorIdentifier(const Identifier: String): TPasIdentifier;
+    function FindAncestorElement(const Identifier: String): TPasElement;
     function FindIdentifier(const Identifier: String): TPasIdentifier; override;
     function FindIdentifier(const Identifier: String): TPasIdentifier; override;
     procedure IterateElements(const aName: string; StartScope: TPasScope;
     procedure IterateElements(const aName: string; StartScope: TPasScope;
       const OnIterateElement: TIterateScopeElement; Data: Pointer;
       const OnIterateElement: TIterateScopeElement; Data: Pointer;
@@ -2846,6 +2848,31 @@ begin
   Result:=false;
   Result:=false;
 end;
 end;
 
 
+function TPasGroupScope.FindAncestorIdentifier(const Identifier: String
+  ): TPasIdentifier;
+var
+  i: Integer;
+begin
+  for i:=1 to Count-1 do
+    begin
+    Result:=Scopes[i].FindIdentifier(Identifier);
+    if Result<>nil then exit;
+    end;
+  Result:=nil;
+end;
+
+function TPasGroupScope.FindAncestorElement(const Identifier: String
+  ): TPasElement;
+var
+  Item: TPasIdentifier;
+begin
+  Item:=FindAncestorIdentifier(Identifier);
+  if Item<>nil then
+    Result:=Item.Element
+  else
+    Result:=nil;
+end;
+
 function TPasGroupScope.FindIdentifier(const Identifier: String
 function TPasGroupScope.FindIdentifier(const Identifier: String
   ): TPasIdentifier;
   ): TPasIdentifier;
 var
 var
@@ -6362,11 +6389,16 @@ var
   procedure GetPropType;
   procedure GetPropType;
   var
   var
     AncEl: TPasElement;
     AncEl: TPasElement;
+    GroupScope: TPasGroupScope;
   begin
   begin
     if PropType<>nil then exit;
     if PropType<>nil then exit;
     AncEl:=nil;
     AncEl:=nil;
     if (ClassScope<>nil) and (ClassScope.AncestorScope<>nil) then
     if (ClassScope<>nil) and (ClassScope.AncestorScope<>nil) then
-      AncEl:=ClassScope.AncestorScope.FindElement(PropEl.Name);
+      begin
+      CheckTopScope(TPasGroupScope);
+      GroupScope:=TPasGroupScope(TopScope);
+      AncEl:=GroupScope.FindAncestorElement(PropEl.Name);
+      end;
     if AncEl is TPasProperty then
     if AncEl is TPasProperty then
       begin
       begin
       // override or redeclaration property
       // override or redeclaration property

+ 21 - 13
packages/fcl-passrc/tests/tcresolver.pas

@@ -11838,19 +11838,27 @@ end;
 procedure TTestResolver.TestPropertyTypeless;
 procedure TTestResolver.TestPropertyTypeless;
 begin
 begin
   StartProgram(false);
   StartProgram(false);
-  Add('type');
-  Add('  {#TOBJ}TObject = class');
-  Add('    {#FB}FB: longint;');
-  Add('    property {#TOBJ_B}B: longint write {@FB}FB;');
-  Add('  end;');
-  Add('  {#TA}TClassA = class');
-  Add('    {#FC}FC: longint;');
-  Add('    property {#TA_B}{@TOBJ_B}B write {@FC}FC;');
-  Add('  end;');
-  Add('var');
-  Add('  {#v}{=TA}v: TClassA;');
-  Add('begin');
-  Add('  {@v}v.{@TA_B}B:=3;');
+  Add([
+  'type',
+  '  {#TOBJ}TObject = class',
+  '    {#FB}FB: longint;',
+  '    property {#TOBJ_B}B: longint write {@FB}FB;',
+  '    property {#TOBJ_D}D: longint write {@FB}FB;',
+  '  end;',
+  '  {#TA}TClassA = class',
+  '    {#FC}FC: longint;',
+  '    property {#TA_B}{@TOBJ_B}B write {@FC}FC;',
+  '  end;',
+  '  {#TB}TClassB = class(TClassA)',
+  '  published',
+  '    property {#TB_D}{@TOBJ_D}D;',
+  '  end;',
+  'var',
+  '  {#v}{=TA}v: TClassA;',
+  'begin',
+  '  {@v}v.{@TA_B}B:=3;',
+  '  {@v}v.{@TObj_D}D:=4;',
+  '']);
   ParseProgram;
   ParseProgram;
 end;
 end;
 
 

+ 2 - 1
packages/pastojs/src/fppas2js.pp

@@ -19821,8 +19821,9 @@ begin
         // create
         // create
         //    GetPathExpr: path1.path2
         //    GetPathExpr: path1.path2
         //    GetExpr:     this.p.readvar
         //    GetExpr:     this.p.readvar
+        //    SetExpr:     this.p.readvar
         // Will create "{p:GetPathExpr, get:function(){return GetExpr;},
         // Will create "{p:GetPathExpr, get:function(){return GetExpr;},
-        //                              set:function(v){GetExpr = v;}}"
+        //                              set:function(v){SetExpr = v;}}"
         GetPathExpr:=CreatePrimitiveDotExpr(LeftStr(GetPath,GetDotPos-1),El);
         GetPathExpr:=CreatePrimitiveDotExpr(LeftStr(GetPath,GetDotPos-1),El);
         GetExpr:=CreatePrimitiveDotExpr('this.'+GetPathName+'.'+copy(GetPath,GetDotPos+1),El);
         GetExpr:=CreatePrimitiveDotExpr('this.'+GetPathName+'.'+copy(GetPath,GetDotPos+1),El);
         if ParamContext.Setter=nil then
         if ParamContext.Setter=nil then

+ 59 - 0
packages/pastojs/tests/tcmodules.pas

@@ -625,6 +625,10 @@ type
     Procedure TestClassInterface_GUID;
     Procedure TestClassInterface_GUID;
     Procedure TestClassInterface_GUIDProperty;
     Procedure TestClassInterface_GUIDProperty;
 
 
+    // helpers
+    Procedure TestClassHelper_ClassVar; // ToDo
+    // todo: TestClassHelper_Overload
+
     // proc types
     // proc types
     Procedure TestProcType;
     Procedure TestProcType;
     Procedure TestProcType_Arg;
     Procedure TestProcType_Arg;
@@ -18345,6 +18349,61 @@ begin
     '']));
     '']));
 end;
 end;
 
 
+procedure TTestModule.TestClassHelper_ClassVar;
+begin
+  exit;
+
+  StartProgram(false);
+  Add([
+  'type',
+  '  TObject = class',
+  '  end;',
+  '  THelper = class helper for TObject',
+  '  const',
+  '    One = 1;',
+  '    Two: word = 2;',
+  '  class var Glob: word;',
+  '  procedure Foo;',
+  '  class procedure Bar;',
+  '  end;',
+  'procedure THelper.foo;',
+  'begin',
+  '  Two:=One;',
+  '  Glob:=Glob;',
+  '  Self.Glob:=Self.Glob;',
+  '  with Self do Self.Glob:=Self.Glob;',
+  'end;',
+  'class procedure THelper.bar;',
+  'begin',
+  '  Two:=One;',
+  '  Glob:=Glob;',
+  '  Self.Glob:=Self.Glob;',
+  '  with Self do Self.Glob:=Self.Glob;',
+  'end;',
+  'var o: TObject;',
+  'begin',
+  '  tobject.two:=tobject.one;',
+  '  tobject.Glob:=tobject.Glob;',
+  '  with tobject do begin',
+  '    two:=one;',
+  '    Glob:=Glob;',
+  '  end;',
+  '  o.two:=o.one;',
+  '  o.Glob:=o.Glob;',
+  '  with o do begin',
+  '    two:=one;',
+  '    Glob:=Glob;',
+  '  end;',
+  '',
+  '']);
+  ConvertProgram;
+  CheckSource('TestClassHelper',
+    LinesToStr([ // statements
+    '']),
+    LinesToStr([ // $mod.$main
+    '']));
+end;
+
 procedure TTestModule.TestProcType;
 procedure TTestModule.TestProcType;
 begin
 begin
   StartProgram(false);
   StartProgram(false);

+ 13 - 5
utils/pas2js/dist/rtl.js

@@ -279,12 +279,16 @@ var rtl = {
       // if root is a "function" then c.$ancestor === c.__proto__, Object.getPrototypeOf(c) returns the root
       // if root is a "function" then c.$ancestor === c.__proto__, Object.getPrototypeOf(c) returns the root
     } else {
     } else {
       c = {};
       c = {};
-      c.$create = function(fnname,args){
+      c.$create = function(fn,args){
         if (args == undefined) args = [];
         if (args == undefined) args = [];
         var o = Object.create(this);
         var o = Object.create(this);
         o.$init();
         o.$init();
         try{
         try{
-          o[fnname].apply(o,args);
+          if (typeof(fn)==="string"){
+            o[fn].apply(o,args);
+          } else {
+            fn.apply(o,args);
+          };
           o.AfterConstruction();
           o.AfterConstruction();
         } catch($e){
         } catch($e){
           // do not call BeforeDestruction
           // do not call BeforeDestruction
@@ -308,17 +312,21 @@ var rtl = {
     // If newinstancefnname is given, use that function to create the new object.
     // If newinstancefnname is given, use that function to create the new object.
     // If exist call BeforeDestruction and AfterConstruction.
     // If exist call BeforeDestruction and AfterConstruction.
     var c = Object.create(ancestor);
     var c = Object.create(ancestor);
-    c.$create = function(fnname,args){
+    c.$create = function(fn,args){
       if (args == undefined) args = [];
       if (args == undefined) args = [];
       var o = null;
       var o = null;
       if (newinstancefnname.length>0){
       if (newinstancefnname.length>0){
-        o = this[newinstancefnname](fnname,args);
+        o = this[newinstancefnname](fn,args);
       } else {
       } else {
         o = Object.create(this);
         o = Object.create(this);
       }
       }
       if (o.$init) o.$init();
       if (o.$init) o.$init();
       try{
       try{
-        o[fnname].apply(o,args);
+        if (typeof(fn)==="string"){
+          o[fn].apply(o,args);
+        } else {
+          fn.apply(o,args);
+        };
         if (o.AfterConstruction) o.AfterConstruction();
         if (o.AfterConstruction) o.AfterConstruction();
       } catch($e){
       } catch($e){
         // do not call BeforeDestruction
         // do not call BeforeDestruction