+ generate external names for methods imported under a different name

* switched to mode delphi to avoid problems with nested types in child
    classes having the same name as nested types in the parent
  * generate skeleton classes for all internal classes that have "package"
    visibility so you can inherit from them (full definitions are not
    possible because that causes circular dependencies)
  -> the entire official JDK 1.5 interface, except for java.awt.Dialog
     (circular dependency with java.awt.Window) can now be generated using
    -a java.awt.Dialog -a sun. -a com.sun. -a apple. -protected java. javax. org.
    (on Mac OS X; the "-a apple." probably has to be changed into something
     else on other platforms)

git-svn-id: branches/jvmbackend@18409 -
This commit is contained in:
Jonas Maebe 2011-08-20 07:57:17 +00:00
parent 94ff4508c7
commit 2a64e411ce
8 changed files with 214 additions and 122 deletions

View File

@ -35,14 +35,26 @@ public class ClassIdentifierInfo {
} }
} }
private String checkSafeIdentifierName(String id) { private static String getMapIdentifer(String id) {
String testName;
if (id.equals("<init>"))
testName = "CREATE";
else if (id.equals("<clinit"))
testName = "CLASSCONSTRUCTOR";
else
testName = id.toUpperCase();
return testName;
}
private String checkSafeIdentifierName(String id, String testName, boolean checkSupers) {
if (checkSupers) {
for (int i = 0; i < superClasses.length; i++) { for (int i = 0; i < superClasses.length; i++) {
id = getSafeIdentifierNameForClass(superClasses[i],id); id = getSafeIdentifierNameForClassInternal(superClasses[i],id,testName,checkSupers);
}
} }
id = PascalKeywords.escapeIfPascalKeyword(id); id = PascalKeywords.escapeIfPascalKeyword(id);
String testName = id.toUpperCase();
String orgName; String orgName;
if (id.indexOf('$') != -1) { if (id.contains("$")) {
System.out.println(" Warning, cannot represent identifier '"+id+"', hiding"); System.out.println(" Warning, cannot represent identifier '"+id+"', hiding");
id = id.replace("$","__"); id = id.replace("$","__");
} }
@ -55,15 +67,18 @@ public class ClassIdentifierInfo {
} }
private String addIdentifier(String id) { private String addIdentifier(String id) {
String testName = id.toUpperCase(); String testName = getMapIdentifer(id);
for (int i = 0; i < superClasses.length; i++) { id = checkSafeIdentifierName(id,testName,true);
id = getSafeIdentifierNameForClass(superClasses[i],id);
}
id = checkSafeIdentifierName(id);
identifiers.put(testName, id); identifiers.put(testName, id);
return id; return id;
} }
private String addMethodIdentifier(String id) {
String testName = getMapIdentifer(id);
id = checkSafeIdentifierName(id,testName,false);
identifiers.put(testName, id);
return id;
}
public static String AddIdentifierNameForClass(String className, String identifier) { public static String AddIdentifierNameForClass(String className, String identifier) {
ClassIdentifierInfo classIdInfo = identifierStore.get(className); ClassIdentifierInfo classIdInfo = identifierStore.get(className);
@ -73,12 +88,42 @@ public class ClassIdentifierInfo {
return classIdInfo.addIdentifier(identifier); return classIdInfo.addIdentifier(identifier);
} }
public static String getSafeIdentifierNameForClass(String className, String identifier) { public static String AddMethodIdentifierNameForClass(String className, String identifier) {
/** all constructors are called <init> and will be renamed to create
* -> any method called create will have to be renamed. This happens automatically
* for classes (since the constructor will be added first), but not for interfaces
* (they don't have a constructor) -> force it here
*/
if (identifier.equals("create"))
identifier = "create_";
ClassIdentifierInfo classIdInfo = identifierStore.get(className); ClassIdentifierInfo classIdInfo = identifierStore.get(className);
if (classIdInfo == null) { if (classIdInfo == null) {
throw new IllegalStateException("Class info for "+className+" not registered"); throw new IllegalStateException("Class info for "+className+" not registered");
} }
return classIdInfo.checkSafeIdentifierName(identifier); return classIdInfo.addMethodIdentifier(identifier);
} }
private static String getSafeIdentifierNameForClassInternal(String className, String identifier, String testName, boolean checkSupers) {
ClassIdentifierInfo classIdInfo = identifierStore.get(className);
if (classIdInfo == null) {
throw new IllegalStateException("Class info for "+className+" not registered");
}
return classIdInfo.checkSafeIdentifierName(identifier,testName,checkSupers);
}
public static String getSafeIdentifierNameForClass(String className, String identifier) {
return getSafeIdentifierNameForClassInternal(className,identifier,getMapIdentifer(identifier),false);
}
public static String getSafeMethodIdentifierNameForClass(String className, String identifier) {
/** all constructors are called <init> and will be renamed to create
* -> any method called create will have to be renamed. This happens automatically
* for classes (since the constructor will be added first), but not for interfaces
* (they don't have a constructor) -> force it here
*/
if (identifier.equals("create"))
identifier = "create_";
return getSafeIdentifierNameForClassInternal(className,identifier,getMapIdentifer(identifier),true);
}
} }

View File

@ -51,15 +51,17 @@ public class JavapPrinter {
PrintWriter out; PrintWriter out;
String prefix; String prefix;
boolean doCollectDependencies; boolean doCollectDependencies;
boolean printOnlySkel;
private ArrayList<JavapPrinter> innerClassPrinters; private ArrayList<JavapPrinter> innerClassPrinters;
public JavapPrinter(InputStream cname, PrintWriter out, JavapEnvironment env, String prefix, PascalClassData outerClass, boolean doCollectDependencies){ public JavapPrinter(InputStream cname, PrintWriter out, JavapEnvironment env, String prefix, PascalClassData outerClass, boolean doCollectDependencies, boolean printOnlySkel){
this.out = out; this.out = out;
this.cls = new PascalClassData(cname,outerClass,env,doCollectDependencies); this.cls = new PascalClassData(cname,outerClass,env,doCollectDependencies);
this.env = env; this.env = env;
this.prefix = prefix; this.prefix = prefix;
this.doCollectDependencies = doCollectDependencies; this.doCollectDependencies = doCollectDependencies;
this.printOnlySkel = printOnlySkel;
innerClassPrinters = new ArrayList<JavapPrinter>(); innerClassPrinters = new ArrayList<JavapPrinter>();
collectInnerClasses(); collectInnerClasses();
} }
@ -69,11 +71,10 @@ public class JavapPrinter {
*/ */
public void print(){ public void print(){
printclassHeader(); printclassHeader();
// avoid some circular dependencies if (!printOnlySkel) {
if ((cls.access & ACC_PUBLIC) != 0) {
printfields(); printfields();
}
printMethods(); printMethods();
}
printend(); printend();
} }
@ -119,6 +120,7 @@ public class JavapPrinter {
out.print("'"+pkgname+"' "); out.print("'"+pkgname+"' ");
out.print("name '"+cls.getExternalClassName()+"' "); out.print("name '"+cls.getExternalClassName()+"' ");
if (!printOnlySkel) {
// FPC doesn't like it when you say that an interface's superclass is // FPC doesn't like it when you say that an interface's superclass is
// java.lang.Object, since that's a class (although at the JVM level // java.lang.Object, since that's a class (although at the JVM level
// it's true) // it's true)
@ -160,7 +162,7 @@ public class JavapPrinter {
} }
if (printedOpeningBracket) if (printedOpeningBracket)
out.print(")"); out.print(")");
}
/* inner classes */ /* inner classes */
printClassAttributes(); printClassAttributes();
} }
@ -295,12 +297,12 @@ public class JavapPrinter {
*/ */
public void printMethodSignature(PascalMethodData method){ public void printMethodSignature(PascalMethodData method){
out.print(prefix); out.print(prefix);
String methodName = method.getName(); String pascalName = method.getName();
if(methodName.equals("<init>")){ if(pascalName.equals("<init>")){
out.print("constructor create"); out.print("constructor create");
out.print(method.getParameters()); out.print(method.getParameters());
}else if(methodName.equals("<clinit>")){ }else if(pascalName.equals("<clinit>")){
out.print("class constructor create"); out.print("class constructor classcreate");
}else{ }else{
String rettype = method.getReturnType(); String rettype = method.getReturnType();
if (method.isStatic()) if (method.isStatic())
@ -309,12 +311,15 @@ public class JavapPrinter {
out.print("procedure "); out.print("procedure ");
else else
out.print("function "); out.print("function ");
out.print(method.getName()); out.print(pascalName);
out.print(method.getParameters()); out.print(method.getParameters());
if (!rettype.equals("")) if (!rettype.equals(""))
out.print(": "+rettype); out.print(": "+rettype);
if (method.isStatic()) if (method.isStatic())
out.print("; static"); out.print("; static");
String externalName = method.getExternalName();
if (externalName != null)
out.print("; external name '"+externalName+"'");
} }
// to fix compilation in Delphi mode // to fix compilation in Delphi mode
out.print("; overload;"); out.print("; overload;");
@ -759,19 +764,9 @@ public class JavapPrinter {
boolean accessOk = checkAccess(accflags); boolean accessOk = checkAccess(accflags);
boolean isStaticInner = inner.isStatic(); boolean isStaticInner = inner.isStatic();
innerPrinter = new JavapPrinter(env.getFileInputStream(javaclassname(innerClassName)), out, env, prefix+" ", cls, innerPrinter = new JavapPrinter(env.getFileInputStream(javaclassname(innerClassName)), out, env, prefix+" ", cls,
doCollectDependencies && accessOk && isStaticInner); doCollectDependencies && accessOk && isStaticInner, printOnlySkel || !accessOk || !isStaticInner);
if(accessOk){
// no support yet for non-static inner classes
if (!isStaticInner) {
// register as external class
PascalClassData.currentUnit.registerInnerClassAsExternalClass(innerClassName);
continue;
}
innerClassPrinters.add(innerPrinter); innerClassPrinters.add(innerPrinter);
} }
else
PascalClassData.currentUnit.registerInnerClassAsExternalClass(innerClassName);
}
} }
} }
} }
@ -780,11 +775,17 @@ public class JavapPrinter {
/** /**
* Print InnerClass attribute information. * Print InnerClass attribute information.
*/ */
private final int VIS_PROTECTED = 0; private final int VIS_PRIVATE = 0;
private final int VIS_PUBLIC = 1; private final int VIS_PACKAGE = 1;
private final int VIS_PROTECTED = 2;
private final int VIS_PUBLIC = 3;
private boolean checkInnerVisibility(int access, int visOk) { private boolean checkInnerVisibility(int access, int visOk) {
switch (visOk) { switch (visOk) {
case VIS_PRIVATE:
return ((access & ACC_PRIVATE) != 0);
case VIS_PACKAGE:
return ((access & (ACC_PUBLIC|ACC_PROTECTED|ACC_PRIVATE)) == 0);
case VIS_PROTECTED: case VIS_PROTECTED:
return ((access & ACC_PROTECTED) != 0); return ((access & ACC_PROTECTED) != 0);
case VIS_PUBLIC: case VIS_PUBLIC:
@ -794,13 +795,28 @@ public class JavapPrinter {
} }
} }
private String visibilitySectionName(int vis) {
switch (vis) {
case VIS_PRIVATE:
return "strict private";
case VIS_PACKAGE:
return "private";
case VIS_PROTECTED:
return "protected";
case VIS_PUBLIC:
return "public";
default:
return "";
}
}
public void printInnerClasses(){//throws ioexception public void printInnerClasses(){//throws ioexception
if (innerClassPrinters.size() > 1) if (innerClassPrinters.size() > 1)
orderInnerClasses(); orderInnerClasses();
if (innerClassPrinters.size() > 0) { if (innerClassPrinters.size() > 0) {
for (int protpub = 0; protpub < 2; protpub++) { for (int protpub = VIS_PACKAGE; protpub <= VIS_PUBLIC; protpub++) {
// no vibility sections in interfaces // no vibility sections in interfaces
boolean first = true; boolean first = true;
for (int i = 0; i < innerClassPrinters.size(); i++) { for (int i = 0; i < innerClassPrinters.size(); i++) {
@ -811,10 +827,7 @@ public class JavapPrinter {
if (first) { if (first) {
if (!cls.isInterface()) { if (!cls.isInterface()) {
out.print(prefix); out.print(prefix);
if (protpub==VIS_PROTECTED) out.println(visibilitySectionName(protpub));
out.println("strict protected");
else
out.println("public");
} }
out.println(innerPrinter.prefix.substring(2)+"type"); out.println(innerPrinter.prefix.substring(2)+"type");
first = false; first = false;
@ -1026,6 +1039,7 @@ public class JavapPrinter {
public void printend(){ public void printend(){
out.println(prefix+"end;"); out.println(prefix+"end;");
out.println();
/* /*
if (cls.isInnerClass()) { if (cls.isInnerClass()) {
String shortName = PascalClassData.getShortClassName(cls.getClassName()); String shortName = PascalClassData.getShortClassName(cls.getClassName());

View File

@ -103,7 +103,7 @@ public class Main{
out.println(" -public Print only public classes and members"); out.println(" -public Print only public classes and members");
out.println(" -protected Print protected/public classes and members"); out.println(" -protected Print protected/public classes and members");
out.println(" -private Show all classes and members"); out.println(" -private Show all classes and members");
out.println(" -x <class_or_pkgename> Do not print a certain classes or package (suffix package names with '.'"); out.println(" -x <class_or_pkgename> Treat this class/package as defined in another unit (suffix package names with '.'");
out.println(" -s Print internal type signatures"); out.println(" -s Print internal type signatures");
out.println(" -bootclasspath <pathlist> Override location of class files loaded"); out.println(" -bootclasspath <pathlist> Override location of class files loaded");
out.println(" by the bootstrap class loader"); out.println(" by the bootstrap class loader");
@ -236,9 +236,13 @@ public class Main{
// collect all class names in the environment (format: /package/name/classname) // collect all class names in the environment (format: /package/name/classname)
SortedSet<String> classes = env.getClassesList(); SortedSet<String> classes = env.getClassesList();
// same for arguments // sort package lists that should/should not be printed
// to optimize checking; combine exclude and skeleton prefixes in one list
Collections.sort(pkgList); Collections.sort(pkgList);
Collections.sort(env.excludePrefixes); ArrayList<String> dontPrintPrefixes = new ArrayList<String>(env.excludePrefixes.size()+env.skelPrefixes.size());
dontPrintPrefixes.addAll(env.excludePrefixes);
dontPrintPrefixes.addAll(env.skelPrefixes);
Collections.sort(dontPrintPrefixes);
// create the unit // create the unit
PrintWriter includeFile; PrintWriter includeFile;
PrintWriter mainUnitFile; PrintWriter mainUnitFile;
@ -262,7 +266,7 @@ public class Main{
// first read all requested classes and build dependency graph // first read all requested classes and build dependency graph
Iterator<String> classStepper = classes.iterator(); Iterator<String> classStepper = classes.iterator();
Iterator<String> argStepper = pkgList.iterator(); Iterator<String> argStepper = pkgList.iterator();
Iterator<String> skipPkgsStepper = env.excludePrefixes.iterator(); Iterator<String> skipPkgsStepper = dontPrintPrefixes.iterator();
HashSet<String> classesToPrintList = new HashSet<String>(); HashSet<String> classesToPrintList = new HashSet<String>();
SimpleDirectedGraph<String,DefaultEdge> classDependencies = new SimpleDirectedGraph<String, DefaultEdge>(DefaultEdge.class); SimpleDirectedGraph<String,DefaultEdge> classDependencies = new SimpleDirectedGraph<String, DefaultEdge>(DefaultEdge.class);
@ -315,7 +319,7 @@ public class Main{
// but only collect dependency information if we actually // but only collect dependency information if we actually
// have to print the class // have to print the class
InputStream classin = env.getFileInputStream(currentClass); InputStream classin = env.getFileInputStream(currentClass);
JavapPrinter printer = new JavapPrinter(classin, includeFile, env, " ",null,doPrintClass); JavapPrinter printer = new JavapPrinter(classin, includeFile, env, " ",null,doPrintClass,true);
if (doPrintClass) { if (doPrintClass) {
if (!classDependencies.containsVertex(currentClass)) if (!classDependencies.containsVertex(currentClass))
classDependencies.addVertex(currentClass); classDependencies.addVertex(currentClass);
@ -354,7 +358,7 @@ public class Main{
continue; continue;
try { try {
InputStream classin = env.getFileInputStream(currentClass); InputStream classin = env.getFileInputStream(currentClass);
JavapPrinter printer = new JavapPrinter(classin, includeFile, env, " ",null, true); JavapPrinter printer = new JavapPrinter(classin, includeFile, env, " ",null, true,false);
printer.print(); printer.print();
// JavapClassPrinter.PrintClass(env,includeFile,currentClass," "); // JavapClassPrinter.PrintClass(env,includeFile,currentClass," ");
@ -378,7 +382,7 @@ public class Main{
try { try {
InputStream classin = env.getFileInputStream(currentClass); InputStream classin = env.getFileInputStream(currentClass);
JavapPrinter printer = new JavapPrinter(classin, includeFile, env, " ",null,true); JavapPrinter printer = new JavapPrinter(classin, includeFile, env, " ",null,true,false);
printer.print(); printer.print();
// JavapClassPrinter.PrintClass(env,includeFile,currentClass," "); // JavapClassPrinter.PrintClass(env,includeFile,currentClass," ");

View File

@ -216,7 +216,7 @@ public class MethodData {
int attr_len=in.readInt(); // attr_length in prog int attr_len=in.readInt(); // attr_length in prog
int num_exceptions = in.readUnsignedShort(); int num_exceptions = in.readUnsignedShort();
exc_index_table=new int[num_exceptions]; exc_index_table=new int[num_exceptions];
int[] exc_index_table=new int[num_exceptions]; // int[] exc_index_table=new int[num_exceptions];
for (int l = 0; l < num_exceptions; l++) { for (int l = 0; l < num_exceptions; l++) {
int exc=in.readShort(); int exc=in.readShort();
exc_index_table[l]=exc; exc_index_table[l]=exc;

View File

@ -40,6 +40,8 @@ public class PascalClassData extends ClassData {
HashSet<String> myDeps = getDependencies(); HashSet<String> myDeps = getDependencies();
String mySuperClass = getSuperClassName(); String mySuperClass = getSuperClassName();
boolean foundMatch = false; boolean foundMatch = false;
String [] interfaces = getSuperInterfaces();
boolean intfMatches[] = new boolean[interfaces.length];
PascalClassData outerMostClass = this; PascalClassData outerMostClass = this;
while (outerMostClass.outerClass != null) { while (outerMostClass.outerClass != null) {
/** /**
@ -57,12 +59,23 @@ public class PascalClassData extends ClassData {
* end; * end;
* -> Retry must depend on Result * -> Retry must depend on Result
*/ */
String outerClassName = outerMostClass.outerClass.getClassName();
if (!foundMatch && if (!foundMatch &&
mySuperClass.startsWith(outerMostClass.outerClass.getClassName()) && mySuperClass.startsWith(outerClassName) &&
!mySuperClass.equals(outerMostClass.outerClass.getClassName())) { !mySuperClass.equals(outerClassName)) {
foundMatch = true; foundMatch = true;
outerMostClass.addNestedDepdency(mySuperClass); outerMostClass.addNestedDepdency(mySuperClass);
} }
for (int i = 0; i < interfaces.length; i++) {
if (!intfMatches[i]) {
String intf = interfaces[i];
if (intf.startsWith(outerClassName) &&
!intf.equals(outerClassName)) {
intfMatches[i] = true;
outerMostClass.addNestedDepdency(intf);
}
}
}
outerMostClass = outerMostClass.outerClass; outerMostClass = outerMostClass.outerClass;
} }
myDeps.remove(outerMostClass.getMasterClassName()); myDeps.remove(outerMostClass.getMasterClassName());

View File

@ -10,7 +10,7 @@ public class PascalKeywords {
} }
static public String escapeIfPascalKeyword(String str) { static public String escapeIfPascalKeyword(String str) {
if (isPascalKeyword(str)) if (isPascalKeyword(str.toUpperCase()))
return "&"+str; return "&"+str;
return str; return str;
} }

View File

@ -61,18 +61,31 @@ public class PascalMethodData extends MethodData {
return ptype; return ptype;
} }
/**
*
* @return if the method requires a separate "external" name due to identifier
* disambiguation, it is returned. Otherwise returns null.
*/
public String getExternalName() {
String realName = super.getName();
// handled separately
if (realName.equals("<init>") ||
realName.equals("<clinit>"))
return null;
String pascalName = getName();
if (pascalName.charAt(0) == '&')
pascalName = pascalName.substring(1);
if (!pascalName.equals(realName)) {
return realName;
} else {
return null;
}
}
public String getName(){ public String getName(){
if (cachedName == null) { if (cachedName == null) {
String realName = super.getName(); String realName = super.getName();
cachedName = ClassIdentifierInfo.AddIdentifierNameForClass(cls.getClassName(),realName); cachedName = ClassIdentifierInfo.AddMethodIdentifierNameForClass(cls.getClassName(),realName);
// this will require compiler support for remapping field names
// (we also need it for Objective-C and C++ anyway)
if ((cachedName.charAt(0) != '&') &&
!cachedName.equals(realName)) {
System.out.println(" Duplicate identifier conflict in "+cls.getClassName()+" for method '"+realName+"', disabled");
}
} }
return cachedName; return cachedName;
} }

View File

@ -293,6 +293,7 @@ public class PascalUnit {
unitFile.println(" "+getShortPascalName(curClass)+" = "+kind+";"); unitFile.println(" "+getShortPascalName(curClass)+" = "+kind+";");
// create formal array types for array parameters // create formal array types for array parameters
printArrayTypes(" ",getShortPascalName(curClass)); printArrayTypes(" ",getShortPascalName(curClass));
unitFile.println();
} }
} }
@ -308,6 +309,7 @@ public class PascalUnit {
unitFile.println(" "+shortPascalName+" = "+kind+" external '"+pkgExternalName+"' name '"+shortExternalName+"';"); unitFile.println(" "+shortPascalName+" = "+kind+" external '"+pkgExternalName+"' name '"+shortExternalName+"';");
// create formal array types for array parameters // create formal array types for array parameters
printArrayTypes(" ",shortPascalName); printArrayTypes(" ",shortPascalName);
unitFile.println();
} }
} }
@ -349,6 +351,7 @@ public class PascalUnit {
shortPascalName = PascalClassData.getShortClassName(curClass); shortPascalName = PascalClassData.getShortClassName(curClass);
} else { } else {
shortPascalName = PascalClassData.getShortPascalClassName(curClass); shortPascalName = PascalClassData.getShortPascalClassName(curClass);
unitFile.println();
} }
unitFile.println(prefix+shortPascalName+" = "+curSkelItem.kind+" external '"+pkgExternalName+"' name '"+shortExternalName+"'"); unitFile.println(prefix+shortPascalName+" = "+curSkelItem.kind+" external '"+pkgExternalName+"' name '"+shortExternalName+"'");
// make sure we only match inner classes, not classes that start with the word in the current package // make sure we only match inner classes, not classes that start with the word in the current package
@ -381,7 +384,7 @@ public class PascalUnit {
} }
unitFile.println(" }"); unitFile.println(" }");
unitFile.println("unit "+env.outputName+";"); unitFile.println("unit "+env.outputName+";");
unitFile.println("{$mode objfpc}"); unitFile.println("{$mode delphi}");
unitFile.println(); unitFile.println();
unitFile.println("interface"); unitFile.println("interface");
unitFile.println(); unitFile.println();