Browse Source

* Empty sections in advanced records

git-svn-id: trunk@47509 -
michael 4 years ago
parent
commit
713d6a0649

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

@@ -534,6 +534,7 @@ type
     procedure ClearTypeReferences(aType: TPasElement); override;
     procedure ClearTypeReferences(aType: TPasElement); override;
   public
   public
     DestType: TPasType;
     DestType: TPasType;
+    SubType: TPasType;
     Expr: TPasExpr;
     Expr: TPasExpr;
   end;
   end;
 
 
@@ -3303,6 +3304,7 @@ end;
 
 
 destructor TPasAliasType.Destroy;
 destructor TPasAliasType.Destroy;
 begin
 begin
+  ReleaseAndNil(TPasElement(SubType){$IFDEF CheckPasTreeRefCount},'TPasAliasType.SubType'{$ENDIF});
   ReleaseAndNil(TPasElement(DestType){$IFDEF CheckPasTreeRefCount},'TPasAliasType.DestType'{$ENDIF});
   ReleaseAndNil(TPasElement(DestType){$IFDEF CheckPasTreeRefCount},'TPasAliasType.DestType'{$ENDIF});
   ReleaseAndNil(TPasElement(Expr){$IFDEF CheckPasTreeRefCount},'TPasAliasType.Expr'{$ENDIF});
   ReleaseAndNil(TPasElement(Expr){$IFDEF CheckPasTreeRefCount},'TPasAliasType.Expr'{$ENDIF});
   inherited Destroy;
   inherited Destroy;

+ 4 - 4
packages/fcl-passrc/src/paswrite.pp

@@ -1408,11 +1408,11 @@ end;
 
 
 procedure TPasWriter.WriteImplRaise(aRaise: TPasImplRaise);
 procedure TPasWriter.WriteImplRaise(aRaise: TPasImplRaise);
 begin
 begin
-  if  assigned(aRaise.ExceptObject) then
+  if assigned(aRaise.ExceptObject) then
     begin
     begin
-      Add('raise %s',[GetExpr(aRaise.ExceptObject)]);
-      if aRaise.ExceptAddr<>Nil then
-        Add(' at %s',[GetExpr(aRaise.ExceptAddr)]);
+    Add('raise %s',[GetExpr(aRaise.ExceptObject)]);
+    if aRaise.ExceptAddr<>Nil then
+      Add(' at %s',[GetExpr(aRaise.ExceptAddr)]);
     end
     end
   else
   else
     Add('raise');
     Add('raise');

+ 36 - 4
packages/fcl-passrc/src/pparser.pp

@@ -1759,12 +1759,20 @@ begin
       end;
       end;
     // read nested specialize arguments
     // read nested specialize arguments
     ReadSpecializeArguments(ST,ST.Params);
     ReadSpecializeArguments(ST,ST.Params);
-    // Important: resolve type reference AFTER args, because arg count is needed
-    ST.DestType:=ResolveTypeReference(GenName,ST,ST.Params.Count);
-
     if CurToken<>tkGreaterThan then
     if CurToken<>tkGreaterThan then
       ParseExcTokenError('[20190801113005]');
       ParseExcTokenError('[20190801113005]');
-    // ToDo: cascaded specialize A<B>.C<D>
+
+    // Check for cascaded specialize A<B>.C or A<B>.C<D>
+    NextToken;
+    if CurToken<>tkDot then
+      UnGetToken
+    else
+      begin
+      NextToken;
+      ST.SubType:=ParseSimpleType(ST,CurSourcePos,GenName,False);
+      end;
+    // Important: resolve type reference AFTER args, because arg count is needed
+    ST.DestType:=ResolveTypeReference(GenName,ST,ST.Params.Count);
 
 
     Engine.FinishScope(stTypeDef,ST);
     Engine.FinishScope(stTypeDef,ST);
     Result:=ST;
     Result:=ST;
@@ -6846,6 +6854,24 @@ var
     Scanner.UnSetTokenOption(toOperatorToken);
     Scanner.UnSetTokenOption(toOperatorToken);
   end;
   end;
 
 
+  Function CheckSection : Boolean;
+
+  begin
+    // Advanced records can have empty sections.
+    { Use Case:
+      Record
+      type
+      const
+      var
+      Case Integer of
+      end;
+    }
+    NextToken;
+    Result:=CurToken in [tkvar,tktype,tkConst,tkCase];
+    if Not Result then
+      UngetToken;
+  end;
+
 Var
 Var
   VariantName : String;
   VariantName : String;
   v : TPasMemberVisibility;
   v : TPasMemberVisibility;
@@ -6874,6 +6900,8 @@ begin
         DisableIsClass;
         DisableIsClass;
         if Not AllowMethods then
         if Not AllowMethods then
           ParseExc(nErrRecordTypesNotAllowed,SErrRecordTypesNotAllowed);
           ParseExc(nErrRecordTypesNotAllowed,SErrRecordTypesNotAllowed);
+        if CheckSection then
+          continue;
         ExpectToken(tkIdentifier);
         ExpectToken(tkIdentifier);
         ParseMembersLocalTypes(ARec,v);
         ParseMembersLocalTypes(ARec,v);
         end;
         end;
@@ -6882,6 +6910,8 @@ begin
         DisableIsClass;
         DisableIsClass;
         if Not AllowMethods then
         if Not AllowMethods then
           ParseExc(nErrRecordConstantsNotAllowed,SErrRecordConstantsNotAllowed);
           ParseExc(nErrRecordConstantsNotAllowed,SErrRecordConstantsNotAllowed);
+        if CheckSection then
+          continue;
         ExpectToken(tkIdentifier);
         ExpectToken(tkIdentifier);
         ParseMembersLocalConsts(ARec,v);
         ParseMembersLocalConsts(ARec,v);
         end;
         end;
@@ -6889,6 +6919,8 @@ begin
         begin
         begin
         if Not AllowMethods then
         if Not AllowMethods then
           ParseExc(nErrRecordVariablesNotAllowed,SErrRecordVariablesNotAllowed);
           ParseExc(nErrRecordVariablesNotAllowed,SErrRecordVariablesNotAllowed);
+        if CheckSection then
+          continue;
         ExpectToken(tkIdentifier);
         ExpectToken(tkIdentifier);
         OldCount:=ARec.Members.Count;
         OldCount:=ARec.Members.Count;
         ParseInlineVarDecl(ARec, ARec.Members, v, AEndToken=tkBraceClose);
         ParseInlineVarDecl(ARec, ARec.Members, v, AEndToken=tkBraceClose);

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

@@ -363,6 +363,8 @@ type
     Procedure TestAdvRec_ProcOverrideFail;
     Procedure TestAdvRec_ProcOverrideFail;
     Procedure TestAdvRec_ProcMessageFail;
     Procedure TestAdvRec_ProcMessageFail;
     Procedure TestAdvRec_DestructorFail;
     Procedure TestAdvRec_DestructorFail;
+    Procedure TestAdvRec_CaseInVar;
+    Procedure TestAdvRec_EmptySections;
     Procedure TestAdvRecordInFunction;
     Procedure TestAdvRecordInFunction;
     Procedure TestAdvRecordInAnonFunction;
     Procedure TestAdvRecordInAnonFunction;
     Procedure TestAdvRecordClassOperator;
     Procedure TestAdvRecordClassOperator;
@@ -2612,6 +2614,29 @@ begin
   ParseRecordFail(SParserNoConstructorAllowed,nParserNoConstructorAllowed);
   ParseRecordFail(SParserNoConstructorAllowed,nParserNoConstructorAllowed);
 end;
 end;
 
 
+procedure TTestRecordTypeParser.TestAdvRec_CaseInVar;
+
+// Found in System.UITypes.pas
+
+begin
+  StartRecord(true);
+  AddMember('var');
+  AddMember('Case Integer of');
+  AddMember('  1 : (x: integer);');
+  AddMember('  2 : (y,z: integer)');
+  ParseRecord;
+end;
+
+procedure TTestRecordTypeParser.TestAdvRec_EmptySections;
+begin
+  StartRecord(true);
+  AddMember('const');
+  AddMember('type');
+  AddMember('var');
+  AddMember('  x: integer;');
+  ParseRecord;
+end;
+
 procedure TTestRecordTypeParser.TestAdvRecordInFunction;
 procedure TTestRecordTypeParser.TestAdvRecordInFunction;
 
 
 // Src from bug report 36179
 // Src from bug report 36179