Browse Source

fcl-passrc: fixed parsing type helper() for, fixed parsing record helper: atype end

git-svn-id: trunk@40869 -
Mattias Gaertner 6 years ago
parent
commit
38f158bb69

+ 3 - 2
packages/fcl-passrc/src/pastree.pp

@@ -733,7 +733,8 @@ type
   TPasGenericTemplateType = Class(TPasType);
   TPasGenericTemplateType = Class(TPasType);
 
 
   TPasObjKind = (
   TPasObjKind = (
-    okObject, okClass, okInterface, okGeneric,
+    okObject, okClass, okInterface,
+    okGeneric, // MG: what is okGeneric?
     // okSpecialize removed in FPC 3.1.1
     // okSpecialize removed in FPC 3.1.1
     okClassHelper,okRecordHelper,okTypeHelper,
     okClassHelper,okRecordHelper,okTypeHelper,
     okDispInterface);
     okDispInterface);
@@ -758,7 +759,7 @@ type
     ObjKind: TPasObjKind;
     ObjKind: TPasObjKind;
     AncestorType: TPasType;   // TPasClassType or TPasUnresolvedTypeRef or TPasAliasType or TPasTypeAliasType
     AncestorType: TPasType;   // TPasClassType or TPasUnresolvedTypeRef or TPasAliasType or TPasTypeAliasType
                               // Note: AncestorType can be nil even though it has a default ancestor
                               // Note: AncestorType can be nil even though it has a default ancestor
-    HelperForType: TPasType;  // TPasClassType or TPasUnresolvedTypeRef
+    HelperForType: TPasType;  // any type, except helper
     IsForward: Boolean;
     IsForward: Boolean;
     IsExternal : Boolean;
     IsExternal : Boolean;
     IsShortDefinition: Boolean;//class(anchestor); without end
     IsShortDefinition: Boolean;//class(anchestor); without end

+ 60 - 34
packages/fcl-passrc/src/pparser.pp

@@ -72,7 +72,7 @@ const
   nParserNotAProcToken = 2026;
   nParserNotAProcToken = 2026;
   nRangeExpressionExpected = 2027;
   nRangeExpressionExpected = 2027;
   nParserExpectCase = 2028;
   nParserExpectCase = 2028;
-  nParserHelperNotAllowed = 2029;
+  // free 2029;
   nLogStartImplementation = 2030;
   nLogStartImplementation = 2030;
   nLogStartInterface = 2031;
   nLogStartInterface = 2031;
   nParserNoConstructorAllowed = 2032;
   nParserNoConstructorAllowed = 2032;
@@ -132,7 +132,7 @@ resourcestring
   SParserNotAProcToken = 'Not a procedure or function token';
   SParserNotAProcToken = 'Not a procedure or function token';
   SRangeExpressionExpected = 'Range expression expected';
   SRangeExpressionExpected = 'Range expression expected';
   SParserExpectCase = 'Case label expression expected';
   SParserExpectCase = 'Case label expression expected';
-  SParserHelperNotAllowed = 'Helper objects not allowed for "%s"';
+  // free for 2029
   SLogStartImplementation = 'Start parsing implementation section.';
   SLogStartImplementation = 'Start parsing implementation section.';
   SLogStartInterface = 'Start parsing interface section';
   SLogStartInterface = 'Start parsing interface section';
   SParserNoConstructorAllowed = 'Constructors or Destructors are not allowed in Interfaces or Record helpers';
   SParserNoConstructorAllowed = 'Constructors or Destructors are not allowed in Interfaces or Record helpers';
@@ -1735,12 +1735,40 @@ begin
       tkInterface:
       tkInterface:
         Result := ParseClassDecl(Parent, NamePos, TypeName, okInterface);
         Result := ParseClassDecl(Parent, NamePos, TypeName, okInterface);
       tkSpecialize: Result:=ParseSpecializeType(Parent,TypeName);
       tkSpecialize: Result:=ParseSpecializeType(Parent,TypeName);
-      tkClass: Result := ParseClassDecl(Parent, NamePos, TypeName, okClass, PM, GenericArgs);
-      tkType:
+      tkClass:
         begin
         begin
+        isHelper:=false;
         NextToken;
         NextToken;
-        isHelper:=CurTokenIsIdentifier('helper');
-        UnGetToken;
+        if CurTokenIsIdentifier('Helper') then
+          begin
+          // class helper: atype end;
+          // class helper for atype end;
+          NextToken;
+          isHelper:=CurToken in [tkfor,tkBraceOpen];
+          UnGetToken;
+          end;
+        UngetToken;
+        if isHelper then
+          Result:=ParseClassDecl(Parent,NamePos,TypeName,okClassHelper,PM, GenericArgs)
+        else
+          Result:=ParseClassDecl(Parent, NamePos, TypeName, okClass, PM, GenericArgs);
+        end;
+      tkType:
+        begin
+        isHelper:=false;
+        if msTypeHelpers in Scanner.CurrentModeSwitches then
+          begin
+          NextToken;
+          if CurTokenIsIdentifier('helper') then
+            begin
+            // atype = type helper;
+            // atype = type helper for atype end;
+            NextToken;
+            isHelper:=CurToken in [tkfor,tkBraceOpen];
+            UnGetToken;
+            end;
+          UnGetToken;
+          end;
         if isHelper then
         if isHelper then
           Result:=ParseClassDecl(Parent,NamePos,TypeName,okTypeHelper,PM)
           Result:=ParseClassDecl(Parent,NamePos,TypeName,okTypeHelper,PM)
         else
         else
@@ -1769,16 +1797,20 @@ begin
       tkRecord:
       tkRecord:
         begin
         begin
         NextToken;
         NextToken;
+        isHelper:=false;
         if CurTokenIsIdentifier('Helper') then
         if CurTokenIsIdentifier('Helper') then
           begin
           begin
+          // record helper: atype end;
+          // record helper for atype end;
+          NextToken;
+          isHelper:=CurToken in [tkfor,tkBraceOpen];
           UnGetToken;
           UnGetToken;
-          Result:=ParseClassDecl(Parent,NamePos,TypeName,okRecordHelper,PM);
-          end
-        else
-          begin
-          UnGetToken;
-          Result := ParseRecordDecl(Parent,NamePos,TypeName,PM);
           end;
           end;
+        UngetToken;
+        if isHelper then
+          Result:=ParseClassDecl(Parent,NamePos,TypeName,okRecordHelper,PM)
+        else
+          Result:=ParseRecordDecl(Parent,NamePos,TypeName,PM);
         end;
         end;
       tkNumber,tkMinus,tkChar:
       tkNumber,tkMinus,tkChar:
         begin
         begin
@@ -6797,18 +6829,23 @@ begin
   if (CurToken=tkBraceOpen) then
   if (CurToken=tkBraceOpen) then
     begin
     begin
     // read ancestor and interfaces
     // read ancestor and interfaces
+    if (AType.ObjKind=okRecordHelper)
+        and ([msTypeHelpers,msDelphi]*Scanner.CurrentModeSwitches=[msDelphi]) then
+      // Delphi does not support ancestors in record helpers
+      CheckToken(tkend);
     NextToken;
     NextToken;
     AType.AncestorType := ParseTypeReference(AType,false,Expr);
     AType.AncestorType := ParseTypeReference(AType,false,Expr);
-    while CurToken=tkComma do
-      begin
-      NextToken;
-      AType.Interfaces.Add(ParseTypeReference(AType,false,Expr));
-      end;
+    if AType.ObjKind in [okClass,okGeneric] then
+      while CurToken=tkComma do
+        begin
+        NextToken;
+        AType.Interfaces.Add(ParseTypeReference(AType,false,Expr));
+        end;
     CheckToken(tkBraceClose);
     CheckToken(tkBraceClose);
     NextToken;
     NextToken;
     AType.IsShortDefinition:=(CurToken=tkSemicolon);
     AType.IsShortDefinition:=(CurToken=tkSemicolon);
     end;
     end;
-  if (AType.ObjKind in [okClassHelper,okRecordHelper]) then
+  if (AType.ObjKind in [okClassHelper,okRecordHelper,okTypeHelper]) then
     begin
     begin
     CheckToken(tkfor);
     CheckToken(tkfor);
     NextToken;
     NextToken;
@@ -6837,12 +6874,10 @@ function TPasParser.ParseClassDecl(Parent: TPasElement;
 
 
 Var
 Var
   ok: Boolean;
   ok: Boolean;
-  FT : TPasType;
   AExternalNameSpace,AExternalName : String;
   AExternalNameSpace,AExternalName : String;
   PCT:TPasClassType;
   PCT:TPasClassType;
 begin
 begin
   NextToken;
   NextToken;
-  FT:=Nil;
   if (AObjKind = okClass) and (CurToken = tkOf) then
   if (AObjKind = okClass) and (CurToken = tkOf) then
     begin
     begin
     Result := TPasClassOfType(CreateElement(TPasClassOfType, AClassName,
     Result := TPasClassOfType(CreateElement(TPasClassOfType, AClassName,
@@ -6860,7 +6895,7 @@ begin
     end;
     end;
     exit;
     exit;
     end;
     end;
-  if ((AObjKind in [okClass,OKInterface]) and (msExternalClass in CurrentModeswitches)
+  if ((AObjKind in [okClass,okInterface]) and (msExternalClass in CurrentModeswitches)
       and CurTokenIsIdentifier('external')) then
       and CurTokenIsIdentifier('external')) then
     begin
     begin
     NextToken;
     NextToken;
@@ -6882,19 +6917,10 @@ begin
     AExternalNameSpace:='';
     AExternalNameSpace:='';
     AExternalName:='';
     AExternalName:='';
     end;
     end;
-  if (CurTokenIsIdentifier('Helper')) then
+  if AObjKind in [okClassHelper,okRecordHelper,okTypeHelper] then
     begin
     begin
-    if Not (AObjKind in [okClass,okTypeHelper,okRecordHelper]) then
-      ParseExc(nParserHelperNotAllowed,SParserHelperNotAllowed,[ObjKindNames[AObjKind]]);
-    Case AObjKind of
-     okClass:
-       AObjKind:=okClassHelper;
-     okTypeHelper:
-       begin
-       ExpectToken(tkFor);
-       FT:=ParseType(Parent,CurSourcePos,'',False);
-       end
-    end;
+    if not CurTokenIsIdentifier('Helper') then
+      ParseExcSyntaxError;
     NextToken;
     NextToken;
     end;
     end;
   PCT := TPasClassType(CreateElement(TPasClassType, AClassName,
   PCT := TPasClassType(CreateElement(TPasClassType, AClassName,
@@ -6902,7 +6928,7 @@ begin
   Result:=PCT;
   Result:=PCT;
   ok:=false;
   ok:=false;
   try
   try
-    PCT.HelperForType:=FT;
+    PCT.HelperForType:=nil;
     PCT.IsExternal:=(AExternalName<>'');
     PCT.IsExternal:=(AExternalName<>'');
     if AExternalName<>'' then
     if AExternalName<>'' then
       PCT.ExternalName:={$ifdef pas2js}DeQuoteString{$else}AnsiDequotedStr{$endif}(AExternalName,'''');
       PCT.ExternalName:={$ifdef pas2js}DeQuoteString{$else}AnsiDequotedStr{$endif}(AExternalName,'''');

+ 8 - 0
packages/fcl-passrc/tests/tctypeparser.pas

@@ -165,6 +165,7 @@ type
     Procedure TestReferencePointer;
     Procedure TestReferencePointer;
     Procedure TestInvalidColon;
     Procedure TestInvalidColon;
     Procedure TestTypeHelper;
     Procedure TestTypeHelper;
+    Procedure TestTypeHelperWithParent;
     procedure TestPointerReference;
     procedure TestPointerReference;
     Procedure TestPointerKeyWord;
     Procedure TestPointerKeyWord;
   end;
   end;
@@ -3562,9 +3563,16 @@ end;
 
 
 procedure TTestTypeParser.TestTypeHelper;
 procedure TTestTypeParser.TestTypeHelper;
 begin
 begin
+  Scanner.CurrentModeSwitches:=Scanner.CurrentModeSwitches+[msTypeHelpers];
   ParseType('Type Helper for AnsiString end',TPasClassType,'');
   ParseType('Type Helper for AnsiString end',TPasClassType,'');
 end;
 end;
 
 
+procedure TTestTypeParser.TestTypeHelperWithParent;
+begin
+  Scanner.CurrentModeSwitches:=Scanner.CurrentModeSwitches+[msTypeHelpers];
+  ParseType('Type Helper(TOtherHelper) for AnsiString end',TPasClassType,'');
+end;
+
 procedure TTestTypeParser.TestPointerReference;
 procedure TTestTypeParser.TestPointerReference;
 begin
 begin
   Add('Type');
   Add('Type');

+ 4 - 10
packages/pastojs/src/fppas2js.pp

@@ -86,7 +86,7 @@ Works:
   - array of record-const
   - array of record-const
   - skip clone record of new record
   - skip clone record of new record
   - use rtl.recNewT to create a record type
   - use rtl.recNewT to create a record type
-  - use TRec.$new to instantiate records
+  - use TRec.$new to instantiate records, using Object.create to instantiate
   - advanced records:
   - advanced records:
     - public, private, strict private
     - public, private, strict private
     - class var
     - class var
@@ -94,6 +94,8 @@ Works:
     - sub types
     - sub types
     - functions
     - functions
     - properties
     - properties
+    - class properties
+    - default property
     - rtti
     - rtti
     - constructor
     - constructor
 - assign: copy values, do not create new JS object, needed by ^record
 - assign: copy values, do not create new JS object, needed by ^record
@@ -376,16 +378,9 @@ Works:
 - move all local types to global
 - move all local types to global
 
 
 ToDos:
 ToDos:
+- class helpers, type helpers, record helpers, array helpers
 - cmd line param to set modeswitch
 - cmd line param to set modeswitch
 - Result:=inherited;
 - Result:=inherited;
-- move local types to unit scope
-- records:
-  - use Object.create to instantiate simple records
-  - advanced records:
-    - class properties
-    - default property
-    - constructor
-    - rtti
 - bug: DoIt(typeinfo(i))  where DoIt is in another unit and has TTypeInfo
 - bug: DoIt(typeinfo(i))  where DoIt is in another unit and has TTypeInfo
 - $OPTIMIZATION ON|OFF
 - $OPTIMIZATION ON|OFF
 - $optimization REMOVEEMPTYPROCS
 - $optimization REMOVEEMPTYPROCS
@@ -445,7 +440,6 @@ ToDos:
   -O2 CSE
   -O2 CSE
   -O3 DFA
   -O3 DFA
 - objects
 - objects
-- class helpers, type helpers, record helpers, array helpers
 - generics
 - generics
 - operator overloading
 - operator overloading
   - operator enumerator
   - operator enumerator