* 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 -
This commit is contained in:
Jonas Maebe 2011-08-20 07:59:40 +00:00
parent fc2d239f95
commit 6dd7d9db41
7 changed files with 156 additions and 65 deletions

View File

@ -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;

View File

@ -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:

View File

@ -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;
}
}

View File

@ -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();
}
/**

View File

@ -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;
}

View File

@ -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();
}
}

View File

@ -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.");
}
}