Pārlūkot izejas kodu

* synchronize with trunk

git-svn-id: branches/unicodekvm@41380 -
nickysn 6 gadi atpakaļ
vecāks
revīzija
a0fed5b9c6

+ 56 - 13
packages/fcl-passrc/src/pparser.pp

@@ -450,7 +450,8 @@ type
     procedure ParseProcBeginBlock(Parent: TProcedureBody);
     procedure ParseProcBeginBlock(Parent: TProcedureBody);
     procedure ParseProcAsmBlock(Parent: TProcedureBody);
     procedure ParseProcAsmBlock(Parent: TProcedureBody);
     // Function/Procedure declaration
     // Function/Procedure declaration
-    function  ParseProcedureOrFunctionDecl(Parent: TPasElement; ProcType: TProcType;AVisibility : TPasMemberVisibility = VisDefault): TPasProcedure;
+    function ParseProcedureOrFunctionDecl(Parent: TPasElement;
+      ProcType: TProcType; MustBeGeneric: boolean; AVisibility: TPasMemberVisibility = VisDefault): TPasProcedure;
     procedure ParseArgList(Parent: TPasElement;
     procedure ParseArgList(Parent: TPasElement;
       Args: TFPList; // list of TPasArgument
       Args: TFPList; // list of TPasArgument
       EndToken: TToken);
       EndToken: TToken);
@@ -2300,7 +2301,7 @@ begin
         ProcType:=ptAnonymousFunction;
         ProcType:=ptAnonymousFunction;
       try
       try
         ProcExpr:=TProcedureExpr(CreateElement(TProcedureExpr,'',AParent,visPublic));
         ProcExpr:=TProcedureExpr(CreateElement(TProcedureExpr,'',AParent,visPublic));
-        ProcExpr.Proc:=TPasAnonymousProcedure(ParseProcedureOrFunctionDecl(ProcExpr,ProcType));
+        ProcExpr.Proc:=TPasAnonymousProcedure(ParseProcedureOrFunctionDecl(ProcExpr,ProcType,false));
         Result:=ProcExpr;
         Result:=ProcExpr;
       finally
       finally
         if Result=nil then
         if Result=nil then
@@ -3413,7 +3414,7 @@ begin
       SetBlock(declNone);
       SetBlock(declNone);
       SaveComments;
       SaveComments;
       pt:=GetProcTypeFromToken(CurToken);
       pt:=GetProcTypeFromToken(CurToken);
-      AddProcOrFunction(Declarations, ParseProcedureOrFunctionDecl(Declarations, pt));
+      AddProcOrFunction(Declarations, ParseProcedureOrFunctionDecl(Declarations, pt, false));
       end;
       end;
     tkClass:
     tkClass:
       begin
       begin
@@ -3423,7 +3424,7 @@ begin
         If CurToken in [tkprocedure,tkFunction,tkConstructor,tkDestructor] then
         If CurToken in [tkprocedure,tkFunction,tkConstructor,tkDestructor] then
           begin
           begin
           pt:=GetProcTypeFromToken(CurToken,True);
           pt:=GetProcTypeFromToken(CurToken,True);
-          AddProcOrFunction(Declarations,ParseProcedureOrFunctionDecl(Declarations, pt));
+          AddProcOrFunction(Declarations,ParseProcedureOrFunctionDecl(Declarations, pt, false));
           end
           end
         else
         else
           CheckToken(tkprocedure);
           CheckToken(tkprocedure);
@@ -3533,9 +3534,8 @@ begin
         end;
         end;
       end;
       end;
     tkGeneric:
     tkGeneric:
-      begin
-        if CurBlock <> declType then
-          ParseExcSyntaxError;
+      if CurBlock = declType then
+        begin
         TypeName := ExpectIdentifier;
         TypeName := ExpectIdentifier;
         NamePos:=CurSourcePos;
         NamePos:=CurSourcePos;
         List:=TFPList.Create;
         List:=TFPList.Create;
@@ -3593,7 +3593,41 @@ begin
             TPasElement(List[i]).Release{$IFDEF CheckPasTreeRefCount}('CreateElement'){$ENDIF};
             TPasElement(List[i]).Release{$IFDEF CheckPasTreeRefCount}('CreateElement'){$ENDIF};
           List.Free;
           List.Free;
         end;
         end;
-      end;
+        end
+      else if CurBlock = declNone then
+        begin
+        if msDelphi in CurrentModeswitches then
+          ParseExcSyntaxError; // inconsistency, tkGeneric should be in Scanner.NonTokens
+        SetBlock(declNone);
+        SaveComments;
+        NextToken;
+        case CurToken of
+        tkclass:
+          begin
+          // generic class ...
+          NextToken;
+          if not (CurToken in [tkprocedure,tkfunction]) then
+            ParseExcSyntaxError;
+          // generic class procedure ...
+          pt:=GetProcTypeFromToken(CurToken,true);
+          AddProcOrFunction(Declarations, ParseProcedureOrFunctionDecl(Declarations, pt, true));
+          end;
+        tkprocedure,tkfunction:
+          begin
+          // generic procedure ...
+          SetBlock(declNone);
+          SaveComments;
+          pt:=GetProcTypeFromToken(CurToken);
+          AddProcOrFunction(Declarations, ParseProcedureOrFunctionDecl(Declarations, pt, true));
+          end;
+        else
+          ParseExcSyntaxError;
+        end;
+        end
+      else
+        begin
+        ParseExcSyntaxError;
+        end;
     tkbegin:
     tkbegin:
       begin
       begin
       if Declarations is TProcedureBody then
       if Declarations is TProcedureBody then
@@ -6112,7 +6146,8 @@ begin
 end;
 end;
 
 
 function TPasParser.ParseProcedureOrFunctionDecl(Parent: TPasElement;
 function TPasParser.ParseProcedureOrFunctionDecl(Parent: TPasElement;
-  ProcType: TProcType; AVisibility: TPasMemberVisibility): TPasProcedure;
+  ProcType: TProcType; MustBeGeneric: boolean; AVisibility: TPasMemberVisibility
+  ): TPasProcedure;
 
 
   function ExpectProcName: string;
   function ExpectProcName: string;
 
 
@@ -6124,13 +6159,15 @@ function TPasParser.ParseProcedureOrFunctionDecl(Parent: TPasElement;
     Result:=ExpectIdentifier;
     Result:=ExpectIdentifier;
     //writeln('ExpectProcName ',Parent.Classname);
     //writeln('ExpectProcName ',Parent.Classname);
     if Parent is TImplementationSection then
     if Parent is TImplementationSection then
-    begin
+      begin
       NextToken;
       NextToken;
       repeat
       repeat
         if CurToken=tkDot then
         if CurToken=tkDot then
           Result:=Result+'.'+ExpectIdentifier
           Result:=Result+'.'+ExpectIdentifier
         else if CurToken=tkLessThan then
         else if CurToken=tkLessThan then
           begin // <> can be ignored, we read the list but discard its content
           begin // <> can be ignored, we read the list but discard its content
+          if (not MustBeGeneric) and not (msDelphi in CurrentModeswitches) then
+            ParseExcTokenError('('); // e.g. "generic" is missing in mode objfpc
           UnGetToken;
           UnGetToken;
           L:=TFPList.Create;
           L:=TFPList.Create;
           Try
           Try
@@ -6146,7 +6183,7 @@ function TPasParser.ParseProcedureOrFunctionDecl(Parent: TPasElement;
         NextToken;
         NextToken;
       until false;
       until false;
       UngetToken;
       UngetToken;
-    end;
+      end;
   end;
   end;
 
 
 var
 var
@@ -6158,6 +6195,8 @@ begin
   case ProcType of
   case ProcType of
   ptOperator,ptClassOperator:
   ptOperator,ptClassOperator:
     begin
     begin
+    if MustBeGeneric then
+      ParseExcTokenError('procedure');
     NextToken;
     NextToken;
     IsTokenBased:=CurToken<>tkIdentifier;
     IsTokenBased:=CurToken<>tkIdentifier;
     if IsTokenBased then
     if IsTokenBased then
@@ -6169,7 +6208,11 @@ begin
     Name:=OperatorNames[Ot];
     Name:=OperatorNames[Ot];
     end;
     end;
   ptAnonymousProcedure,ptAnonymousFunction:
   ptAnonymousProcedure,ptAnonymousFunction:
+    begin
     Name:='';
     Name:='';
+    if MustBeGeneric then
+      ParseExcTokenError('generic'); // inconsistency
+    end
   else
   else
     Name:=ExpectProcName;
     Name:=ExpectProcName;
   end;
   end;
@@ -6376,7 +6419,7 @@ begin
         if Not AllowMethods then
         if Not AllowMethods then
           ParseExc(nErrRecordMethodsNotAllowed,SErrRecordMethodsNotAllowed);
           ParseExc(nErrRecordMethodsNotAllowed,SErrRecordMethodsNotAllowed);
         ProcType:=GetProcTypeFromToken(CurToken,isClass);
         ProcType:=GetProcTypeFromToken(CurToken,isClass);
-        Proc:=ParseProcedureOrFunctionDecl(ARec,ProcType,v);
+        Proc:=ParseProcedureOrFunctionDecl(ARec,ProcType,false,v);
         if Proc.Parent is TPasOverloadedProc then
         if Proc.Parent is TPasOverloadedProc then
           TPasOverloadedProc(Proc.Parent).Overloads.Add(Proc)
           TPasOverloadedProc(Proc.Parent).Overloads.Add(Proc)
         else
         else
@@ -6519,7 +6562,7 @@ var
   ProcType: TProcType;
   ProcType: TProcType;
 begin
 begin
   ProcType:=GetProcTypeFromToken(CurToken,isClass);
   ProcType:=GetProcTypeFromToken(CurToken,isClass);
-  Proc:=ParseProcedureOrFunctionDecl(AType,ProcType,AVisibility);
+  Proc:=ParseProcedureOrFunctionDecl(AType,ProcType,false,AVisibility);
   if Proc.Parent is TPasOverloadedProc then
   if Proc.Parent is TPasOverloadedProc then
     TPasOverloadedProc(Proc.Parent).Overloads.Add(Proc)
     TPasOverloadedProc(Proc.Parent).Overloads.Add(Proc)
   else
   else

+ 6 - 0
packages/fcl-passrc/src/pscanner.pp

@@ -3400,9 +3400,15 @@ begin
   'OBJFPC':
   'OBJFPC':
     SetMode(msObjfpc,OBJFPCModeSwitches,true,bsObjFPCMode);
     SetMode(msObjfpc,OBJFPCModeSwitches,true,bsObjFPCMode);
   'DELPHI':
   'DELPHI':
+    begin
     SetMode(msDelphi,DelphiModeSwitches,true,bsDelphiMode,[bsPointerMath]);
     SetMode(msDelphi,DelphiModeSwitches,true,bsDelphiMode,[bsPointerMath]);
+    SetNonToken(tkgeneric);
+    end;
   'DELPHIUNICODE':
   'DELPHIUNICODE':
+    begin
     SetMode(msDelphiUnicode,DelphiUnicodeModeSwitches,true,bsDelphiUnicodeMode,[bsPointerMath]);
     SetMode(msDelphiUnicode,DelphiUnicodeModeSwitches,true,bsDelphiUnicodeMode,[bsPointerMath]);
+    SetNonToken(tkgeneric);
+    end;
   'TP':
   'TP':
     SetMode(msTP7,TPModeSwitches,false);
     SetMode(msTP7,TPModeSwitches,false);
   'MACPAS':
   'MACPAS':

+ 1 - 2
packages/fcl-passrc/tests/tcgenerics.pp

@@ -219,13 +219,12 @@ end;
 
 
 procedure TTestGenerics.TestGenericFunction;
 procedure TTestGenerics.TestGenericFunction;
 begin
 begin
-  exit; // ToDo
   Add([
   Add([
   'generic function IfThen<T>(val:boolean;const iftrue:T; const iffalse:T) :T; inline; overload;',
   'generic function IfThen<T>(val:boolean;const iftrue:T; const iffalse:T) :T; inline; overload;',
   'begin',
   'begin',
   'end;',
   'end;',
   'begin',
   'begin',
-  '  IfThen<word>(true,2,3);',
+  '  specialize IfThen<word>(true,2,3);',
   '']);
   '']);
   ParseModule;
   ParseModule;
 end;
 end;

+ 16 - 2
utils/pas2jni/writer.pas

@@ -1451,6 +1451,8 @@ begin
     if d.ProcType = ptFunction then
     if d.ProcType = ptFunction then
       s:=Format('Result:=%s', [JniToPasType(d.ReturnType, s, False)]);
       s:=Format('Result:=%s', [JniToPasType(d.ReturnType, s, False)]);
     Fps.WriteLn(s + ';');
     Fps.WriteLn(s + ';');
+    // Java exception check
+    Fps.WriteLn('_HandleJavaException(_env);');
     // Processing var/out parameters
     // Processing var/out parameters
     for i:=0 to d.Count - 1 do begin
     for i:=0 to d.Count - 1 do begin
       vd:=TVarDef(d[i]);
       vd:=TVarDef(d[i]);
@@ -1851,6 +1853,8 @@ begin
       Fps.WriteLn('var mpi: _TMethodPtrInfo;');
       Fps.WriteLn('var mpi: _TMethodPtrInfo;');
       Fps.WriteLn('begin');
       Fps.WriteLn('begin');
       Fps.IncI;
       Fps.IncI;
+      Fps.WriteLn('Result:=nil;');
+      Fps.WriteLn('if (m.Data = nil) and (m.Code = nil) then exit;');
       Fps.WriteLn('_MethodPointersCS.Enter;');
       Fps.WriteLn('_MethodPointersCS.Enter;');
       Fps.WriteLn('try');
       Fps.WriteLn('try');
       Fps.IncI;
       Fps.IncI;
@@ -2184,6 +2188,8 @@ begin
   Fps.WriteLn('Result:=JNI_ERR;');
   Fps.WriteLn('Result:=JNI_ERR;');
   Fps.WriteLn('if vm^^.GetEnv(vm, @env, JNI_VERSION_1_6) <> JNI_OK then exit;');
   Fps.WriteLn('if vm^^.GetEnv(vm, @env, JNI_VERSION_1_6) <> JNI_OK then exit;');
   Fps.WriteLn('CurJavaVM:=vm;');
   Fps.WriteLn('CurJavaVM:=vm;');
+  Fps.WriteLn('_JavaExceptionClass:=env^^.FindClass(env, ''java/lang/Exception'');');
+  Fps.WriteLn('if _JavaExceptionClass = nil then exit;');
 
 
   d:=TTypeDef.Create(nil, dtType);
   d:=TTypeDef.Create(nil, dtType);
   try
   try
@@ -2964,7 +2970,6 @@ begin
     Fps.WriteLn('begin');
     Fps.WriteLn('begin');
     Fps.WriteLn('Result:=_CreateJavaObj(env, jlong(ptruint(PasObj)), ci, cleanup)', 1);
     Fps.WriteLn('Result:=_CreateJavaObj(env, jlong(ptruint(PasObj)), ci, cleanup)', 1);
     Fps.WriteLn('end;');
     Fps.WriteLn('end;');
-    Fps.WriteLn;
 
 
     Fps.WriteLn;
     Fps.WriteLn;
     Fps.WriteLn('function _GetPasObj(env: PJNIEnv; jobj: jobject; const ci: _TJavaClassInfo; CheckNil: boolean): pointer;');
     Fps.WriteLn('function _GetPasObj(env: PJNIEnv; jobj: jobject; const ci: _TJavaClassInfo; CheckNil: boolean): pointer;');
@@ -2997,14 +3002,23 @@ begin
     Fps.DecI;
     Fps.DecI;
     Fps.WriteLn('end;');
     Fps.WriteLn('end;');
 
 
+    Fps.WriteLn;
+    Fps.WriteLn('var _JavaExceptionClass: jclass;');
     Fps.WriteLn;
     Fps.WriteLn;
     Fps.WriteLn('procedure _HandleJNIException(env: PJNIEnv);');
     Fps.WriteLn('procedure _HandleJNIException(env: PJNIEnv);');
     Fps.WriteLn('begin');
     Fps.WriteLn('begin');
+    Fps.WriteLn('if env^^.ExceptionCheck(env) <> 0 then exit;', 1);
     if p.OnExceptionProc <> nil then begin
     if p.OnExceptionProc <> nil then begin
       Fps.WriteLn(Format('%s.%s;', [p.OnExceptionProc.Parent.Name, p.OnExceptionProc.Name]), 1);
       Fps.WriteLn(Format('%s.%s;', [p.OnExceptionProc.Parent.Name, p.OnExceptionProc.Name]), 1);
       p.OnExceptionProc.SetNotUsed;
       p.OnExceptionProc.SetNotUsed;
     end;
     end;
-    Fps.WriteLn('env^^.ThrowNew(env, env^^.FindClass(env, ''java/lang/Exception''), PAnsiChar(Utf8Encode(Exception(ExceptObject).Message)));', 1);
+    Fps.WriteLn('env^^.ThrowNew(env, _JavaExceptionClass, PAnsiChar(Utf8Encode(Exception(ExceptObject).Message)));', 1);
+    Fps.WriteLn('end;');
+
+    Fps.WriteLn;
+    Fps.WriteLn('procedure _HandleJavaException(env: PJNIEnv);');
+    Fps.WriteLn('begin');
+    Fps.WriteLn('if env^^.ExceptionCheck(env) <> 0 then raise Exception.Create(''Java exception.'');', 1);
     Fps.WriteLn('end;');
     Fps.WriteLn('end;');
 
 
     Fps.WriteLn;
     Fps.WriteLn;