+ 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) {
for (int i = 0; i < superClasses.length; i++) {
id = getSafeIdentifierNameForClass(superClasses[i],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++) {
id = getSafeIdentifierNameForClassInternal(superClasses[i],id,testName,checkSupers);
}
}
id = PascalKeywords.escapeIfPascalKeyword(id);
String testName = id.toUpperCase();
String orgName;
if (id.indexOf('$') != -1) {
if (id.contains("$")) {
System.out.println(" Warning, cannot represent identifier '"+id+"', hiding");
id = id.replace("$","__");
}
@ -55,16 +67,19 @@ public class ClassIdentifierInfo {
}
private String addIdentifier(String id) {
String testName = id.toUpperCase();
for (int i = 0; i < superClasses.length; i++) {
id = getSafeIdentifierNameForClass(superClasses[i],id);
}
id = checkSafeIdentifierName(id);
String testName = getMapIdentifer(id);
id = checkSafeIdentifierName(id,testName,true);
identifiers.put(testName, 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) {
ClassIdentifierInfo classIdInfo = identifierStore.get(className);
if (classIdInfo == null) {
@ -73,12 +88,42 @@ public class ClassIdentifierInfo {
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);
if (classIdInfo == null) {
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;
String prefix;
boolean doCollectDependencies;
boolean printOnlySkel;
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.cls = new PascalClassData(cname,outerClass,env,doCollectDependencies);
this.env = env;
this.prefix = prefix;
this.doCollectDependencies = doCollectDependencies;
this.printOnlySkel = printOnlySkel;
innerClassPrinters = new ArrayList<JavapPrinter>();
collectInnerClasses();
}
@ -69,11 +71,10 @@ public class JavapPrinter {
*/
public void print(){
printclassHeader();
// avoid some circular dependencies
if ((cls.access & ACC_PUBLIC) != 0) {
if (!printOnlySkel) {
printfields();
printMethods();
}
printMethods();
printend();
}
@ -101,66 +102,67 @@ public class JavapPrinter {
}
// the actual class/interface
out.print(prefix);
if(cls.isInterface()) {
// The only useful access modifier of an interface is
// public; interfaces are always marked as abstract and
// cannot be final.
out.print(shortname + " = interface ");
}
else if(cls.isClass()) {
out.print(shortname+" = class ");
String []accflags = cls.getModifiers();
printAccess(accflags);
}
if(cls.isInterface()) {
// The only useful access modifier of an interface is
// public; interfaces are always marked as abstract and
// cannot be final.
out.print(shortname + " = interface ");
}
else if(cls.isClass()) {
out.print(shortname+" = class ");
String []accflags = cls.getModifiers();
printAccess(accflags);
}
out.print("external ");
String pkgname = cls.getClassPackageName();
if (pkgname != null)
out.print("'"+pkgname+"' ");
out.print("name '"+cls.getExternalClassName()+"' ");
// 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
// it's true)
boolean printedOpeningBracket = false;
String superClass = cls.getSuperClassName();
if((superClass != null) &&
(cls.isClass() ||
!PascalClassData.getShortPascalClassName(superClass).equals("JLObject"))){
printedOpeningBracket = true;
String fullPascalSuperClass = PascalClassData.getFullPascalClassName(superClass);
String reducedPascalSuperClass = fullPascalSuperClass;
if (!PascalClassData.currentUnit.isExternalInnerClass(superClass) &&
((PascalClassData)cls).outerClass != null) {
reducedPascalSuperClass = fullPascalSuperClass.replace(((PascalClassData)cls).outerClass.getShortPascalClassName()+".","");
}
if (reducedPascalSuperClass.equals(fullPascalSuperClass)) {
out.print("(" + PascalClassData.getShortPascalClassName(superClass));
} else {
out.print("(" + reducedPascalSuperClass);
}
}
out.print("external ");
String pkgname = cls.getClassPackageName();
if (pkgname != null)
out.print("'"+pkgname+"' ");
out.print("name '"+cls.getExternalClassName()+"' ");
String []interfacelist = cls.getPascalSuperInterfaces();
if(interfacelist.length > 0){
// assume all classes that implement interfaces inherit from
// a class (correct, since java.lang.Object does not implement
// any interfaces
if (!printedOpeningBracket) {
out.print("(");
printedOpeningBracket=true;
out.print(interfacelist[0]);
}
else
out.print(", "+interfacelist[0]);
for(int j = 1; j < interfacelist.length; j++){
out.print(", "+interfacelist[j]);
}
}
if (printedOpeningBracket)
out.print(")");
if (!printOnlySkel) {
// 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
// it's true)
boolean printedOpeningBracket = false;
String superClass = cls.getSuperClassName();
if((superClass != null) &&
(cls.isClass() ||
!PascalClassData.getShortPascalClassName(superClass).equals("JLObject"))){
printedOpeningBracket = true;
String fullPascalSuperClass = PascalClassData.getFullPascalClassName(superClass);
String reducedPascalSuperClass = fullPascalSuperClass;
if (!PascalClassData.currentUnit.isExternalInnerClass(superClass) &&
((PascalClassData)cls).outerClass != null) {
reducedPascalSuperClass = fullPascalSuperClass.replace(((PascalClassData)cls).outerClass.getShortPascalClassName()+".","");
}
if (reducedPascalSuperClass.equals(fullPascalSuperClass)) {
out.print("(" + PascalClassData.getShortPascalClassName(superClass));
} else {
out.print("(" + reducedPascalSuperClass);
}
}
String []interfacelist = cls.getPascalSuperInterfaces();
if(interfacelist.length > 0){
// assume all classes that implement interfaces inherit from
// a class (correct, since java.lang.Object does not implement
// any interfaces
if (!printedOpeningBracket) {
out.print("(");
printedOpeningBracket=true;
out.print(interfacelist[0]);
}
else
out.print(", "+interfacelist[0]);
for(int j = 1; j < interfacelist.length; j++){
out.print(", "+interfacelist[j]);
}
}
if (printedOpeningBracket)
out.print(")");
}
/* inner classes */
printClassAttributes();
}
@ -295,12 +297,12 @@ public class JavapPrinter {
*/
public void printMethodSignature(PascalMethodData method){
out.print(prefix);
String methodName = method.getName();
if(methodName.equals("<init>")){
String pascalName = method.getName();
if(pascalName.equals("<init>")){
out.print("constructor create");
out.print(method.getParameters());
}else if(methodName.equals("<clinit>")){
out.print("class constructor create");
}else if(pascalName.equals("<clinit>")){
out.print("class constructor classcreate");
}else{
String rettype = method.getReturnType();
if (method.isStatic())
@ -309,12 +311,15 @@ public class JavapPrinter {
out.print("procedure ");
else
out.print("function ");
out.print(method.getName());
out.print(pascalName);
out.print(method.getParameters());
if (!rettype.equals(""))
out.print(": "+rettype);
if (method.isStatic())
out.print("; static");
String externalName = method.getExternalName();
if (externalName != null)
out.print("; external name '"+externalName+"'");
}
// to fix compilation in Delphi mode
out.print("; overload;");
@ -759,18 +764,8 @@ public class JavapPrinter {
boolean accessOk = checkAccess(accflags);
boolean isStaticInner = inner.isStatic();
innerPrinter = new JavapPrinter(env.getFileInputStream(javaclassname(innerClassName)), out, env, prefix+" ", cls,
doCollectDependencies && 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);
}
else
PascalClassData.currentUnit.registerInnerClassAsExternalClass(innerClassName);
doCollectDependencies && accessOk && isStaticInner, printOnlySkel || !accessOk || !isStaticInner);
innerClassPrinters.add(innerPrinter);
}
}
}
@ -780,11 +775,17 @@ public class JavapPrinter {
/**
* Print InnerClass attribute information.
*/
private final int VIS_PROTECTED = 0;
private final int VIS_PUBLIC = 1;
private final int VIS_PRIVATE = 0;
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) {
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:
return ((access & ACC_PROTECTED) != 0);
case VIS_PUBLIC:
@ -793,14 +794,29 @@ public class JavapPrinter {
return false;
}
}
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
if (innerClassPrinters.size() > 1)
if (innerClassPrinters.size() > 1)
orderInnerClasses();
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
boolean first = true;
for (int i = 0; i < innerClassPrinters.size(); i++) {
@ -811,10 +827,7 @@ public class JavapPrinter {
if (first) {
if (!cls.isInterface()) {
out.print(prefix);
if (protpub==VIS_PROTECTED)
out.println("strict protected");
else
out.println("public");
out.println(visibilitySectionName(protpub));
}
out.println(innerPrinter.prefix.substring(2)+"type");
first = false;
@ -1026,6 +1039,7 @@ public class JavapPrinter {
public void printend(){
out.println(prefix+"end;");
out.println();
/*
if (cls.isInnerClass()) {
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(" -protected Print protected/public 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(" -bootclasspath <pathlist> Override location of class files loaded");
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)
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(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
PrintWriter includeFile;
PrintWriter mainUnitFile;
@ -262,7 +266,7 @@ public class Main{
// first read all requested classes and build dependency graph
Iterator<String> classStepper = classes.iterator();
Iterator<String> argStepper = pkgList.iterator();
Iterator<String> skipPkgsStepper = env.excludePrefixes.iterator();
Iterator<String> skipPkgsStepper = dontPrintPrefixes.iterator();
HashSet<String> classesToPrintList = new HashSet<String>();
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
// have to print the class
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 (!classDependencies.containsVertex(currentClass))
classDependencies.addVertex(currentClass);
@ -354,7 +358,7 @@ public class Main{
continue;
try {
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();
// JavapClassPrinter.PrintClass(env,includeFile,currentClass," ");
@ -378,7 +382,7 @@ public class Main{
try {
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();
// JavapClassPrinter.PrintClass(env,includeFile,currentClass," ");

View File

@ -216,7 +216,7 @@ public class MethodData {
int attr_len=in.readInt(); // attr_length in prog
int num_exceptions = in.readUnsignedShort();
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++) {
int exc=in.readShort();
exc_index_table[l]=exc;

View File

@ -40,6 +40,8 @@ public class PascalClassData extends ClassData {
HashSet<String> myDeps = getDependencies();
String mySuperClass = getSuperClassName();
boolean foundMatch = false;
String [] interfaces = getSuperInterfaces();
boolean intfMatches[] = new boolean[interfaces.length];
PascalClassData outerMostClass = this;
while (outerMostClass.outerClass != null) {
/**
@ -57,12 +59,23 @@ public class PascalClassData extends ClassData {
* end;
* -> Retry must depend on Result
*/
String outerClassName = outerMostClass.outerClass.getClassName();
if (!foundMatch &&
mySuperClass.startsWith(outerMostClass.outerClass.getClassName()) &&
!mySuperClass.equals(outerMostClass.outerClass.getClassName())) {
mySuperClass.startsWith(outerClassName) &&
!mySuperClass.equals(outerClassName)) {
foundMatch = true;
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;
}
myDeps.remove(outerMostClass.getMasterClassName());
@ -369,7 +382,7 @@ public class PascalClassData extends ClassData {
return new PascalInnerClassData(this);
}
public HashSet<String> getDependencies() {
public HashSet<String> getDependencies() {
HashSet<String> res = new HashSet<String>();
// inheritance dependencies (superclass and implemented interfaces)
String superClass = getSuperClassName();

View File

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

View File

@ -61,18 +61,31 @@ public class PascalMethodData extends MethodData {
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(){
if (cachedName == null) {
String realName = super.getName();
cachedName = ClassIdentifierInfo.AddIdentifierNameForClass(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");
}
cachedName = ClassIdentifierInfo.AddMethodIdentifierNameForClass(cls.getClassName(),realName);
}
return cachedName;
}

View File

@ -293,6 +293,7 @@ public class PascalUnit {
unitFile.println(" "+getShortPascalName(curClass)+" = "+kind+";");
// create formal array types for array parameters
printArrayTypes(" ",getShortPascalName(curClass));
unitFile.println();
}
}
@ -308,6 +309,7 @@ public class PascalUnit {
unitFile.println(" "+shortPascalName+" = "+kind+" external '"+pkgExternalName+"' name '"+shortExternalName+"';");
// create formal array types for array parameters
printArrayTypes(" ",shortPascalName);
unitFile.println();
}
}
@ -349,6 +351,7 @@ public class PascalUnit {
shortPascalName = PascalClassData.getShortClassName(curClass);
} else {
shortPascalName = PascalClassData.getShortPascalClassName(curClass);
unitFile.println();
}
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
@ -381,7 +384,7 @@ public class PascalUnit {
}
unitFile.println(" }");
unitFile.println("unit "+env.outputName+";");
unitFile.println("{$mode objfpc}");
unitFile.println("{$mode delphi}");
unitFile.println();
unitFile.println("interface");
unitFile.println();