Browse Source

fcl-passrc: fixed checking statement after except-on

git-svn-id: trunk@48211 -
(cherry picked from commit b460f87fd425c853769e9d63e3ec0e239f8cba79)
Mattias Gaertner 4 years ago
parent
commit
6c23750094

+ 11 - 3
packages/fcl-passrc/src/pasresolver.pp

@@ -3937,10 +3937,16 @@ end;
 { EPasResolve }
 
 procedure EPasResolve.SetPasElement(AValue: TPasElement);
+var
+  Old: TPasElement;
 begin
   if FPasElement=AValue then Exit;
-  if PasElement<>nil then
+  Old:=FPasElement;
+  if Old<>nil then
+    begin
+    Old:=nil;
     PasElement.Release{$IFDEF CheckPasTreeRefCount}('EPasResolve.SetPasElement'){$ENDIF};
+    end;
   FPasElement:=AValue;
   if PasElement<>nil then
     PasElement.AddRef{$IFDEF CheckPasTreeRefCount}('EPasResolve.SetPasElement'){$ENDIF};
@@ -7526,11 +7532,13 @@ procedure TPasResolver.FinishExceptOnExpr;
 var
   El: TPasImplExceptOn;
   ResolvedType: TPasResolverResult;
+  TypeEl: TPasType;
 begin
   CheckTopScope(TPasExceptOnScope);
   El:=TPasImplExceptOn(FTopScope.Element);
-  ComputeElement(El.TypeEl,ResolvedType,[rcType]);
-  CheckIsClass(El.TypeEl,ResolvedType);
+  TypeEl:=El.TypeEl;
+  ComputeElement(TypeEl,ResolvedType,[rcType]);
+  CheckIsClass(TypeEl,ResolvedType);
 end;
 
 procedure TPasResolver.FinishExceptOnStatement;

+ 28 - 10
packages/fcl-passrc/src/pparser.pp

@@ -6001,10 +6001,23 @@ var
 
   function CloseBlock: boolean; // true if parent reached
   var C: TPasImplBlockClass;
+    NeedUnget: Boolean;
   begin
     C:=TPasImplBlockClass(CurBlock.ClassType);
     if C=TPasImplExceptOn then
-      Engine.FinishScope(stExceptOnStatement,CurBlock)
+      begin
+      Engine.FinishScope(stExceptOnStatement,CurBlock);
+      NeedUnget:=CurToken=tkSemicolon;
+      if NeedUnget then
+        NextToken;
+      if (CurToken in [tkend,tkelse])
+          or ((CurToken=tkIdentifier) and (lowercase(CurTokenString)='on')) then
+        // ok
+      else
+        ParseExcExpectedAorB('end','on');
+      if NeedUnget then
+        UngetToken;
+      end
     else if C=TPasImplWithDo then
       Engine.FinishScope(stWithExpr,CurBlock);
     CurBlock:=CurBlock.Parent as TPasImplBlock;
@@ -6063,6 +6076,7 @@ var
   TypeEl: TPasType;
   ImplRaise: TPasImplRaise;
   VarEl: TPasVariable;
+  ImplExceptOn: TPasImplExceptOn;
 
 begin
   NewImplElement:=nil;
@@ -6486,6 +6500,8 @@ begin
         //        ParseExc;
         CheckStatementCanStart;
 
+        //writeln('TPasParser.ParseStatement ',CurToken,' ',CurTokenString);
+
         // On is usable as an identifier
         if lowerCase(CurTokenText)='on' then
           begin
@@ -6496,31 +6512,33 @@ begin
             begin
               SrcPos:=CurTokenPos;
               ExpectIdentifier;
-              El:=TPasImplExceptOn(CreateElement(TPasImplExceptOn,'',CurBlock,SrcPos));
+              ImplExceptOn:=TPasImplExceptOn(CreateElement(TPasImplExceptOn,'',CurBlock,SrcPos));
+              El:=ImplExceptOn;
               SrcPos:=CurSourcePos;
               Name:=CurTokenString;
               NextToken;
+              //writeln('TPasParser.ParseStatement ',CurToken,' ',CurTokenString);
               //writeln('ON t=',Name,' Token=',CurTokenText);
               if CurToken=tkColon then
                 begin
                 // the first expression was the variable name
                 NextToken;
-                TypeEl:=ParseSimpleType(El,SrcPos,'');
-                TPasImplExceptOn(El).TypeEl:=TypeEl;
-                VarEl:=TPasVariable(CreateElement(TPasVariable,Name,El,SrcPos));
-                TPasImplExceptOn(El).VarEl:=VarEl;
+                TypeEl:=ParseSimpleType(ImplExceptOn,SrcPos,'');
+                ImplExceptOn.TypeEl:=TypeEl;
+                VarEl:=TPasVariable(CreateElement(TPasVariable,Name,ImplExceptOn,SrcPos));
+                ImplExceptOn.VarEl:=VarEl;
                 VarEl.VarType:=TypeEl;
                 TypeEl.AddRef{$IFDEF CheckPasTreeRefCount}('TPasVariable.VarType'){$ENDIF};
-                if TypeEl.Parent=El then
+                if TypeEl.Parent=ImplExceptOn then
                   TypeEl.Parent:=VarEl;
                 end
               else
                 begin
                 UngetToken;
-                TPasImplExceptOn(El).TypeEl:=ParseSimpleType(El,SrcPos,'');
+                ImplExceptOn.TypeEl:=ParseSimpleType(ImplExceptOn,SrcPos,'');
                 end;
-              Engine.FinishScope(stExceptOnExpr,El);
-              CreateBlock(TPasImplExceptOn(El));
+              Engine.FinishScope(stExceptOnExpr,ImplExceptOn);
+              CreateBlock(ImplExceptOn);
               El:=nil;
               ExpectToken(tkDo);
             end else

+ 22 - 0
packages/fcl-passrc/tests/tcresolver.pas

@@ -345,6 +345,7 @@ type
     Procedure TestTryStatement;
     Procedure TestTryExceptOnNonTypeFail;
     Procedure TestTryExceptOnNonClassFail;
+    Procedure TestTryStatementMissingOnFail;
     Procedure TestRaiseNonVarFail;
     Procedure TestRaiseNonClassFail;
     Procedure TestRaiseDescendant;
@@ -1736,6 +1737,8 @@ begin
         end;
       ok:=true;
       end;
+    on E: Exception do
+      Fail('Expected EPasResolve but got '+E.ClassName);
   end;
   AssertEquals('Missing resolver error {'+Msg+'} ('+IntToStr(MsgNumber)+')',true,ok);
 end;
@@ -1756,6 +1759,8 @@ begin
         MsgNumber,Parser.LastMsgNumber);
       ok:=true;
       end;
+    on E: Exception do
+      Fail('Expected EParserError but got '+E.ClassName);
   end;
   AssertEquals('Missing parser error '+Msg+' ('+IntToStr(MsgNumber)+')',true,ok);
 end;
@@ -5414,6 +5419,23 @@ begin
   CheckResolverException('class expected, but Longint found',nXExpectedButYFound);
 end;
 
+procedure TTestResolver.TestTryStatementMissingOnFail;
+begin
+  StartProgram(true,[supTObject]);
+  Add([
+  'procedure Run;',
+  'begin',
+  '  try',
+  '  except',
+  '    on TObject do ;',
+  '    Run;',
+  '  end;',
+  'end;',
+  'begin',
+  '']);
+  CheckParserException('Expected "end" or "on"',nParserExpectToken2Error);
+end;
+
 procedure TTestResolver.TestRaiseNonVarFail;
 begin
   StartProgram(false);