Forráskód Böngészése

* generate a declaration with an dynamic array and one with an open array
parameter in case of array parameters (and in case of constructors,
make the open array as "const"; heuristic, not guaranteed 100% safe!)
+ support for generating include files rather than full units (e.g., for
the system unit types), -i option
* don't generate imports for anonymous inner types ($1 etc)
* mark routines with 'package' visibility as 'public', because some packages
are split over multiple units (system unit and jdk import unit) -> allows
using these routines in illegal ways, which will result in run time errors
+ support to also select individual classes with the -x/-a parameters
+ add "virtual" modifier to methods where appropriate (so the compiler won't
force it automatically anymore)

git-svn-id: branches/jvmbackend@18439 -

Jonas Maebe 14 éve
szülő
commit
6dd7d9db41

+ 1 - 0
utils/javapp/src/fpc/tools/javapp/JavapEnvironment.java

@@ -71,6 +71,7 @@ public class JavapEnvironment {
     boolean extDirflag;
     boolean nothingToDo = true;
     boolean showallAttr = false;
+    boolean generateInclude = false;
     String classpath = null;
     String outputName = "java";
     ArrayList<String> excludePrefixes;

+ 51 - 21
utils/javapp/src/fpc/tools/javapp/JavapPrinter.java

@@ -282,11 +282,6 @@ public class JavapPrinter {
             		prevVis=newVis;
             	}
                 printMethodSignature(method);
-                // all interface methods are marked as "abstract", and cannot be final
-                if (!cls.isInterface())
-                	out.print(method.getModifiers());
-                printExceptions(method);
-                out.println();
             }
         }
         prefix=prefix.substring(2);
@@ -296,33 +291,60 @@ public class JavapPrinter {
      * Print method signature.
      */
     public void printMethodSignature(PascalMethodData method){
-    	out.print(prefix);
+    	StringBuilder sigStart = new StringBuilder();
+    	StringBuilder sigEnd;
+    	sigStart.append(prefix);
     	String pascalName = method.getName();
         if(pascalName.equals("<init>")){
-            out.print("constructor create");
-            out.print(method.getParameters());
+        	sigStart.append("constructor create");
+        	sigEnd = new StringBuilder();
+            // to fix compilation in Delphi mode
+        	sigEnd.append("; overload;");
+        	String dynArrParas = method.getParameters(false,true);
+        	String openArrParas = method.getParameters(true,true);
+            out.print(sigStart+dynArrParas+sigEnd);
+            printExceptions(method);
+            out.println();
+        	if (!dynArrParas.equals(openArrParas)) {
+        		out.print(sigStart+openArrParas+sigEnd);
+                printExceptions(method);
+                out.println();
+        	}
         }else if(pascalName.equals("<clinit>")){
-            out.print("class constructor classcreate");
+        	sigStart.append("class constructor classcreate");
         }else{
         	String rettype = method.getReturnType();
         	if (method.isStatic())
-        		out.print("class ");
+        		sigStart.append("class ");
         	if (rettype.equals(""))
-        		out.print("procedure ");
+        		sigStart.append("procedure ");
         	else
-        		out.print("function ");
-            out.print(pascalName);
-            out.print(method.getParameters());
+        		sigStart.append("function ");
+        	sigStart.append(pascalName);
+        	sigEnd = new StringBuilder();
             if (!rettype.equals(""))
-            	out.print(": "+rettype);
+            	sigEnd.append(": "+rettype);
         	if (method.isStatic())
-        		out.print("; static");
+        		sigEnd.append("; static");
         	String externalName = method.getExternalName();
         	if (externalName != null)
-        		out.print("; external name '"+externalName+"'");
+        		sigEnd.append("; external name '"+externalName+"'");
+            // to fix compilation in Delphi mode
+        	sigEnd.append("; overload;");
+            // all interface methods are marked as "abstract", and cannot be final
+            if (!cls.isInterface())
+            	sigEnd.append(method.getModifiers());
+        	String dynArrParas = method.getParameters(false,false);
+        	String openArrParas = method.getParameters(true,false);
+        	out.print(sigStart+dynArrParas+sigEnd);
+            printExceptions(method);
+            out.println();
+        	if (!dynArrParas.equals(openArrParas)) {
+        		out.print(sigStart+openArrParas+sigEnd);
+                printExceptions(method);
+                out.println();
+        	}
         }
-        // to fix compilation in Delphi mode
-        out.print("; overload;");
     }
 
     /**
@@ -760,7 +782,12 @@ public class JavapPrinter {
             		String[] accflags = innerClasses[i].getAccess();
             		PascalInnerClassData inner = (PascalInnerClassData)innerClasses[i];
             		String innerClassName = cls.StringValue(inner.inner_class_info_index);
-            		if (innerClassName.startsWith(curClassName+"$")){
+            		// * inner class names that do not begin with this class' name are
+            		//   unrelated to this class (they're nested somewhere else)
+            		// * inner class names that start with 0-9 are anonymous
+            		if (innerClassName.startsWith(curClassName+"$") &&
+            				!((innerClassName.charAt(curClassName.length()+1) >= '0') &&
+            						(innerClassName.charAt(curClassName.length()+1) <= '9'))) {
             			boolean accessOk = checkAccess(accflags);
             			boolean isStaticInner = inner.isStatic();
             			innerPrinter = new JavapPrinter(env.getFileInputStream(javaclassname(innerClassName)), out, env, prefix+"    ", cls,
@@ -800,7 +827,10 @@ public class JavapPrinter {
 		case VIS_PRIVATE:
 			return "strict private";
 		case VIS_PACKAGE:
-			return "private";
+			// should be "private", but then won't work for classes of the
+			// same package declared in different units, which happens
+			// at least for the classes in the system unit...
+			return "public";
 		case VIS_PROTECTED:
 			return "protected";
 		case VIS_PUBLIC:

+ 29 - 17
utils/javapp/src/fpc/tools/javapp/Main.java

@@ -32,6 +32,7 @@ package fpc.tools.javapp;
 
 import java.util.*;
 import java.io.*;
+import java.nio.charset.Charset;
 
 import org.jgrapht.alg.CycleDetector;
 import org.jgrapht.graph.*;
@@ -98,6 +99,7 @@ public class Main{
 		out.println("   -classpath <pathlist>     Specify where to find user class files");
 		out.println("   -help                     Print this usage message");
 		out.println("   -J<flag>                  Pass <flag> directly to the runtime system");
+		out.println("   -i                        Generate include files instead of complete unit");
 		out.println("   -l                        Print line number and local variable tables");
 		out.println("   -o <output_base_name>     Base name of output unit (default: java");
 		out.println("   -public                   Print only public classes and members");
@@ -134,6 +136,8 @@ public class Main{
 					env.showVerbose = true;
 				} else if (arg.equals("-v")) {
 					env.showVerbose = true;
+				} else if (arg.equals("-i"))  {
+					env.generateInclude = true;
 				} else if (arg.equals("-h")) {
 					error("-h is no longer available - use the 'javah' program");
 					return false;
@@ -249,7 +253,11 @@ public class Main{
 		PascalUnit thisUnit;
 		String includeName, mainUnitName;
 
-		mainUnitName = env.outputName+".pas";
+		if (env.generateInclude) {
+			mainUnitName = env.outputName+"h.inc";
+		} else {
+			mainUnitName = env.outputName+".pas";			
+		}
 		includeName = env.outputName+".inc";
 
 		includeFile = createFile(includeName);
@@ -272,45 +280,49 @@ public class Main{
 
 		try {
 			String currentExcludePkg; 
-			String currentPkgPrefix;
+			String currentPrefix;
 			if (skipPkgsStepper.hasNext())
 				currentExcludePkg = skipPkgsStepper.next();
 			else
 				currentExcludePkg = ".......";
-			if (argStepper.hasNext())
-				currentPkgPrefix = argStepper.next().replace('.', '/');
-			else
-				currentPkgPrefix = ".......";
-			System.out.println("Indexing classes under "+currentPkgPrefix+"...");
+			if (argStepper.hasNext()) {
+				currentPrefix = argStepper.next();
+				if (!currentPrefix.equals(".")) {
+					currentPrefix = currentPrefix.replace('.', '/');
+				} else {
+					currentPrefix = "./";
+				}
+			} else
+				currentPrefix = ".......";
+			System.out.println("Indexing classes under "+currentPrefix+"...");
 			do {
 				String currentClass = classStepper.next();
 				// if the current class name is > the current package name, skip packages
 				// until we have a package to which the current class belongs, or the
 				// next in line
 				while (argStepper.hasNext() &&
-						!currentClass.startsWith(currentPkgPrefix) &&
-						(currentClass.compareTo(currentPkgPrefix) > 0)) {
+						!PascalUnit.classOrPackageInPrefix(currentClass,currentPrefix) &&
+						(currentClass.compareTo(currentPrefix) > 0)) {
 					String currentArg = argStepper.next();
-					// convention: '.' as package name = no package name, otherwise actual package name
 					if (!currentArg.equals(".")) {
 						currentArg = currentArg.replace('.', '/');
-						currentPkgPrefix = currentArg;
+						currentPrefix = currentArg;
 					} else {
 						currentArg = "./";
-						currentPkgPrefix = currentArg;
+						currentPrefix = currentArg;
 					}
-					System.out.println("Indexing classes under "+currentPkgPrefix+"...");
-					currentPkgPrefix = currentArg;
+					System.out.println("Indexing classes under "+currentPrefix+"...");
+					currentPrefix = currentArg;
 				}
 				boolean doPrintClass = false;
 				// should check whether the class is explicitly excluded from being printed
-				if (currentClass.startsWith(currentPkgPrefix)) {
+				if (PascalUnit.classOrPackageInPrefix(currentClass,currentPrefix)) {
 					while (skipPkgsStepper.hasNext() &&
-							!currentClass.startsWith(currentExcludePkg) &&
+							!PascalUnit.classOrPackageInPrefix(currentClass,currentExcludePkg) &&
 							(currentClass.compareTo(currentExcludePkg) > 0)) {
 						currentExcludePkg = skipPkgsStepper.next();
 					}
-					if (!currentClass.startsWith(currentExcludePkg)) {
+					if (!PascalUnit.classOrPackageInPrefix(currentClass,currentExcludePkg)) {
 						doPrintClass = true;
 					}
 				}

+ 1 - 1
utils/javapp/src/fpc/tools/javapp/PascalFieldData.java

@@ -46,7 +46,7 @@ public class PascalFieldData extends FieldData {
      * Returns Pascal type signature of a field.
      */
     public String getType(){
-        return new PascalTypeSignature(getInternalSig(),cls).getFieldType();
+        return new PascalTypeSignature(getInternalSig(),cls,false,false).getFieldType();
     }
 
     /**

+ 6 - 5
utils/javapp/src/fpc/tools/javapp/PascalMethodData.java

@@ -26,8 +26,9 @@ public class PascalMethodData extends MethodData {
      * Return modifiers of the method that matter to Pascal import.
      */
     public String getModifiers(){
-        if ((access & ACC_FINAL)    !=0) return " final;";
-        if ((access & ACC_ABSTRACT) !=0) return " abstract;";
+        if ((access & ACC_FINAL)    !=0) return " virtual; final;";
+        if ((access & ACC_ABSTRACT) !=0) return " virtual; abstract;";
+        if (!isStatic()) return " virtual;";
         return "";
     }
 
@@ -36,7 +37,7 @@ public class PascalMethodData extends MethodData {
      */
     public String getReturnType(){
 
-        String rttype = (new PascalTypeSignature(getInternalSig(), cls)).getReturnType();
+        String rttype = (new PascalTypeSignature(getInternalSig(), cls, false, false)).getReturnType();
         return rttype;
     }
 
@@ -55,8 +56,8 @@ public class PascalMethodData extends MethodData {
     /**
      * Return java type parameter signature.
      */
-    public String getParameters(){
-        String ptype = (new PascalTypeSignature(getInternalSig(),cls)).getParameters();
+    public String getParameters(boolean useOpenArrays, boolean useConstOpenArrays){
+        String ptype = (new PascalTypeSignature(getInternalSig(),cls,useOpenArrays,useConstOpenArrays)).getParameters();
 
         return ptype;
     }

+ 31 - 7
utils/javapp/src/fpc/tools/javapp/PascalTypeSignature.java

@@ -3,8 +3,17 @@ package fpc.tools.javapp;
 import java.util.Vector;
 
 public class PascalTypeSignature extends TypeSignature {
+	
+	// use open arrays rather than dynamic arrays for array parameters
+	private boolean useOpenArrays;
+	// when creating open array parameters, declare them as "const" rather than var
+	// (done for constructors, under the assumption that these won't change the
+	//  incoming data)
+	private boolean useConstOpenArrays;
 
-	public PascalTypeSignature(String JVMSignature, ClassData cls) {
+	public PascalTypeSignature(String JVMSignature, ClassData cls, boolean useOpenArrays, boolean useConstOpenArrays) {
+		this.useOpenArrays = useOpenArrays;
+		this.useConstOpenArrays = useConstOpenArrays;
 		init(JVMSignature);
 	}
 
@@ -74,7 +83,11 @@ public class PascalTypeSignature extends TypeSignature {
             }else {
                 componentType = getBaseType(arrayType);
             }
-            return outerClass+"Arr"+dimCount+componentType;
+            if (!useOpenArrays ||
+            		(dimCount>1))
+            	return outerClass+"Arr"+dimCount+componentType;
+            else
+            	return "array of "+outerClass+componentType;
         }
         return null;
     }
@@ -84,17 +97,28 @@ public class PascalTypeSignature extends TypeSignature {
         /* number of arguments of a method.*/
         argumentlength =  parameters.size();
         /* Pascal type signature.*/
-        String parametersignature = "(";
+        StringBuilder parametersignature = new StringBuilder("(");
         int i;
         
         for(i = 0; i < argumentlength; i++){
-        	parametersignature += "para"+(i+1)+": "+(String)parameters.elementAt(i);
+        	String paraType = (String)parameters.elementAt(i);
+        	// contents of open arrays could be changed -> var parameters
+        	if (paraType.contains("array of")) {
+        		if (!useConstOpenArrays)
+        		  parametersignature.append("var ");
+        		else
+          		  parametersignature.append("const ");
+        	}
+        	parametersignature.append("para");
+        	parametersignature.append(i+1);
+        	parametersignature.append(": ");
+        	parametersignature.append(paraType);
             if(i != parameters.size()-1){
-                parametersignature += "; ";
+                parametersignature.append("; ");
             }
         }
-        parametersignature += ")";
-        return parametersignature;
+        parametersignature.append(")");
+        return parametersignature.toString();
     }
     
 }

+ 37 - 14
utils/javapp/src/fpc/tools/javapp/PascalUnit.java

@@ -170,6 +170,25 @@ public class PascalUnit {
 		}
 	}
 
+	/**
+	 * 
+	 * @param currentName name to check
+	 * @param currentPrefix if prefix ends in '.' or '/', assumed to be package, otherwise class
+	 * @return whether currentName is a class inside currentPrefix
+	 */
+	public static boolean classOrPackageInPrefix(String currentName, String currentPrefix) {
+		boolean res = currentName.startsWith(currentPrefix);
+		char lastPrefixChar = currentPrefix.charAt(currentPrefix.length()-1);
+		if ((lastPrefixChar != '.') &&
+				(lastPrefixChar != '/')) {
+			res &=
+				(currentName.length() == currentPrefix.length()) ||
+				((currentName.length() > currentPrefix.length()) &&
+						(currentName.charAt(currentPrefix.length()) == '$'));
+		}
+		return res;
+	}
+	
 		
 	public void registerUsedClass(String className) {
 		className = className.replace('.','/');
@@ -181,7 +200,7 @@ public class PascalUnit {
 		isSkel = false;
 		// first check for skeleton classes/packages
 		for (int i = 0; i < skelPrefixes.length; i++) {
-			if (className.startsWith(skelPrefixes[i])) {
+			if (classOrPackageInPrefix(className,skelPrefixes[i])) {
 				isSkel = true;
 				break;
 			}
@@ -194,11 +213,11 @@ public class PascalUnit {
 			// check whether we should fully print it; if not,
 			// declare as anonymous external
 			for (int i = 0; i < pkgPrefixes.length; i++) {
-				if (className.startsWith(pkgPrefixes[i])) {
+				if (classOrPackageInPrefix(className,pkgPrefixes[i])) {
 					boolean excluded = false;
 					// then excluded
 					for (int j = 0; j < excludePrefixes.length; j++) {
-						if (className.startsWith(excludePrefixes[j])) {
+						if (classOrPackageInPrefix(className,excludePrefixes[j])) {
 							excluded = true;
 							break;
 						}
@@ -378,16 +397,18 @@ public class PascalUnit {
 		Enumeration<String> strIterator;
 		Enumeration<SkelItem> skelIterator;
 		
-		unitFile.print("{ Imports for Java packages: "+RealPkgName(pkgPrefixes[0]));
+		unitFile.print("{ Imports for Java packages/classes: "+RealPkgName(pkgPrefixes[0]));
 		for (int i = 1; i < pkgPrefixes.length; i++) {
 			unitFile.print(", "+RealPkgName(pkgPrefixes[i]));
 		}
 		unitFile.println(" }");
-		unitFile.println("unit "+env.outputName+";");
-		unitFile.println("{$mode delphi}");
-		unitFile.println();
-		unitFile.println("interface");
-		unitFile.println();
+		if (!env.generateInclude) {
+			unitFile.println("unit "+env.outputName+";");
+			unitFile.println("{$mode delphi}");
+			unitFile.println();
+			unitFile.println("interface");
+			unitFile.println();
+		}
 		unitFile.println("type");
 		// forward declaration for all classes/interfaces in this package
 		strIterator = Collections.enumeration(registeredInternalClasses);
@@ -402,11 +423,13 @@ public class PascalUnit {
 		skelIterator = Collections.enumeration(registeredSkelObjs);
 		printSkelObjs(skelIterator);
 		unitFile.println();
-		unitFile.println("{$include "+includeName+"}");
-		unitFile.println();
-		unitFile.println("implementation");
-		unitFile.println();
-		unitFile.println("end.");
+		if (!env.generateInclude) {
+			unitFile.println("{$include "+includeName+"}");
+			unitFile.println();
+			unitFile.println("implementation");
+			unitFile.println();
+			unitFile.println("end.");
+		}
 	}