diff --git a/utils/javapp/src/fpc/tools/javapp/JavapEnvironment.java b/utils/javapp/src/fpc/tools/javapp/JavapEnvironment.java index 8f1abc390f..20b03534d2 100644 --- a/utils/javapp/src/fpc/tools/javapp/JavapEnvironment.java +++ b/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 excludePrefixes; diff --git a/utils/javapp/src/fpc/tools/javapp/JavapPrinter.java b/utils/javapp/src/fpc/tools/javapp/JavapPrinter.java index 7bae31dd37..9c32de1f0d 100644 --- a/utils/javapp/src/fpc/tools/javapp/JavapPrinter.java +++ b/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("")){ - 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("")){ - 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: diff --git a/utils/javapp/src/fpc/tools/javapp/Main.java b/utils/javapp/src/fpc/tools/javapp/Main.java index 0448d7a671..67c24ee692 100644 --- a/utils/javapp/src/fpc/tools/javapp/Main.java +++ b/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 Specify where to find user class files"); out.println(" -help Print this usage message"); out.println(" -J Pass 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 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; } } diff --git a/utils/javapp/src/fpc/tools/javapp/PascalFieldData.java b/utils/javapp/src/fpc/tools/javapp/PascalFieldData.java index 1738a74135..0cdbb639b1 100644 --- a/utils/javapp/src/fpc/tools/javapp/PascalFieldData.java +++ b/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(); } /** diff --git a/utils/javapp/src/fpc/tools/javapp/PascalMethodData.java b/utils/javapp/src/fpc/tools/javapp/PascalMethodData.java index ebf3e2d21a..92d4a96d6b 100644 --- a/utils/javapp/src/fpc/tools/javapp/PascalMethodData.java +++ b/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; } diff --git a/utils/javapp/src/fpc/tools/javapp/PascalTypeSignature.java b/utils/javapp/src/fpc/tools/javapp/PascalTypeSignature.java index 8425e231a3..7fe76e1a9d 100644 --- a/utils/javapp/src/fpc/tools/javapp/PascalTypeSignature.java +++ b/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(); } } diff --git a/utils/javapp/src/fpc/tools/javapp/PascalUnit.java b/utils/javapp/src/fpc/tools/javapp/PascalUnit.java index 5bdc0061d7..ad2cc4fb28 100644 --- a/utils/javapp/src/fpc/tools/javapp/PascalUnit.java +++ b/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 strIterator; Enumeration 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."); + } }