X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=src%2Fjava%2Forg%2Fibex%2Ftool%2FCompiler.java;h=8d10ce35fb33d3add67fb9bd321ba19ed3653c2c;hb=283369d4f4fbde8d91dc99f9b365db57671ab2d5;hp=a9e6b0c77e650a7f79cb0c8f12614a86777f22b9;hpb=79e341b630359d9cbc7e950cf7a8768ee0515a8b;p=org.ibex.tool.git diff --git a/src/java/org/ibex/tool/Compiler.java b/src/java/org/ibex/tool/Compiler.java index a9e6b0c..8d10ce3 100644 --- a/src/java/org/ibex/tool/Compiler.java +++ b/src/java/org/ibex/tool/Compiler.java @@ -15,41 +15,112 @@ import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy; import org.eclipse.jdt.internal.compiler.IProblemFactory; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException; -import org.eclipse.jdt.internal.compiler.env.IBinaryField; -import org.eclipse.jdt.internal.compiler.env.IBinaryMethod; -import org.eclipse.jdt.internal.compiler.env.IBinaryNestedType; -import org.eclipse.jdt.internal.compiler.env.IBinaryType; -import org.eclipse.jdt.internal.compiler.env.ICompilationUnit; -import org.eclipse.jdt.internal.compiler.env.INameEnvironment; -import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer; -import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; -import org.eclipse.jdt.internal.compiler.impl.Constant; +import org.eclipse.jdt.internal.compiler.env.*; +import org.eclipse.jdt.internal.compiler.impl.*; import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory; public class Compiler { + private static final boolean DEBUG = false; + + // Static Entry Point ///////////////////////////////////////////////////// + + public static void main(String[] args) { + String source = null, target = null; + String srcdir = null, blddir = null; + + for (int i=0; i < args.length; i++) { + if (args[i].charAt(0) == '-') { + if (args[i].length() == 1) { + System.out.println("Illegal switch: -"); return; } + switch (args[i].charAt(1)) { + case '-': + if (args[i].equals("--help")) printHelp(); + else System.out.println("Unknown switch: -"); + return; + case 'd': + if (i == args.length - 1) { + System.out.println("Missing parameter: "+args[i]); return; } + blddir = args[++i]; + break; + case 's': + if (i == args.length - 1) { + System.out.println("Missing parameter: "+args[i]); return; } + source = args[++i]; + break; + case 't': + if (i == args.length - 1) { + System.out.println("Missing parameter: "+args[i]); return; } + target = args[++i]; + break; + case 'h': + printHelp(); return; + + } + } else srcdir = args[i]; + } + + Compiler c = new Compiler(); + if (blddir != null) c.setBuildDir(blddir); + if (srcdir != null) c.setSourceDir(srcdir); + if (source != null) c.setSource(source); + if (target != null) c.setTarget(target); + c.compile(); + } + private static void printHelp() { + System.out.println("Usage java -cp ... org.ibex.tool.Compiler "); + System.out.println("Options:"); + System.out.println(" -d Location for generated class files."); + System.out.println(" -s Compile with specified source compatibility."); + System.out.println(" -t Compile with specified class file compatibility."); + System.out.println(" -h or --help Print this message."); + System.out.println(""); + } + + + // Compiler Interface ///////////////////////////////////////////////////// private ClassLoader loader = ClassLoader.getSystemClassLoader(); private Map loaded = new HashMap(); - private Writer out = new PrintWriter(System.out); - private Preprocessor preprocessor = new Preprocessor(null, null, Collections.EMPTY_LIST); + private PrintWriter out = new PrintWriter(System.out); + private Preprocessor preprocessor; private Source[] sources; - private ICompilationUnit[] units; + private File builddir = new File("."); + private File sourcedir = new File("."); - public static void main(String[] args) { - new Compiler(args); + public Compiler() { + List defs = Collections.EMPTY_LIST; + + String define = System.getProperty("org.ibex.tool.preprocessor.define"); + if (define != null) { + defs = new ArrayList(); + StringTokenizer st = new StringTokenizer(define.toUpperCase(), ","); + while (st.hasMoreTokens()) defs.add(st.nextToken().trim()); + } + + preprocessor = new Preprocessor(null, null, defs); } - public Compiler(String[] files) { - sources = new Source[files.length]; - units = new ICompilationUnit[files.length]; - for (int i=0; i < files.length; i++) { - char[][] n = classname(files[i]); - sources[i] = new Source(new File(files[i]), name(n), pack(n)); - units[i] = sources[i].unit; - } + public void setBuildDir(String dir) { builddir = new File(dir == null ? "." : dir); } + public void setSourceDir(String dir) { sourcedir = new File(dir == null ? "." : dir); } + + /** Pass CompilerOptions.VERSION_1_*. A String of form "1.1", ".2", etc. */ + public void setSource(String v) { settings.put(CompilerOptions.OPTION_Source, v); } + + /** Pass CompilerOptions.VERSION_1_*. A String of form "1.1", ".2", etc. */ + public void setTarget(String v) { settings.put(CompilerOptions.OPTION_TargetPlatform, v); } + + public void setBuilddir(File f) { builddir = f; } + + public void compile() { + List s = new ArrayList(); + filterSources(s, sourcedir, new char[0][]); + if (DEBUG) System.out.println("working with "+s.size() +" sources"); + sources = new Source[s.size()]; s.toArray(sources); + ICompilationUnit[] units = new ICompilationUnit[s.size()]; + for (int i=0; i < sources.length; i++) units[i] = sources[i].unit; org.eclipse.jdt.internal.compiler.Compiler jdt = new org.eclipse.jdt.internal.compiler.Compiler( @@ -57,8 +128,77 @@ public class Compiler { jdt.compile(units); } + private final FilenameFilter filterSrcs = new FilenameFilter() { + public boolean accept(File dir, String name) { return name.endsWith(".java"); } + }; + private final FileFilter filterDirs = new FileFilter() { + public boolean accept(File path) { return path.isDirectory(); } + }; + private void filterSources(List s, File dir, char[][] pack) { + File[] ja = dir.listFiles(filterSrcs); + for (int i=0; i < ja.length; i++) + s.add(new Source(ja[i], name(classname(ja[i].getName())), pack)); + + File[] d = dir.listFiles(filterDirs); + for (int i=0; i < d.length; i++) { + char[][] newpack = new char[pack.length + 1][]; + for (int j=0; j < pack.length; j++) newpack[j] = pack[j]; + newpack[pack.length] = d[i].getName().toCharArray(); + filterSources(s, d[i], newpack); + } + } + - // Compiler Parameters //////////////////////////////////////////////////// + /** Represents a file to be compiled. */ + final class Source { + char[] fileName; + char[] n; char[][] p; + File orig; + char[] processed = null; + byte[] compiled = null; + + final ICompilationUnit unit = new ICompilationUnit() { + public char[] getMainTypeName() { return n; } + public char[][] getPackageName() { return p; } + public char[] getFileName() { return fileName; } + public char[] getContents() { + if (processed != null) return processed; + + try { + Reader r = new InputStreamReader(new BufferedInputStream( + new FileInputStream(orig))); + StringWriter w = new StringWriter(); + Vector err; + + synchronized (preprocessor) { + preprocessor.setReader(r); + preprocessor.setWriter(w); + err = preprocessor.process(); + } + + if (err.size() > 0) { + System.out.println("Preprocessor Errors, "+err); // FIXME + return null; + } + + processed = w.toString().toCharArray(); + } catch (IOException e) { + System.out.println("IOException: "+e); // FIXME + return null; + } + + return processed; + } + }; + + private Source(File o, char[] n, char[][] p) { + orig = o; this.n = n; this.p = p; + try { fileName = orig.getCanonicalPath().toCharArray(); } // FIXME: dont use full path + catch (IOException e) { fileName = orig.getName().toCharArray(); } + } + } + + // ClassLoader Wrappers /////////////////////////////////////////////////// final static class LoadedNestedType implements IBinaryNestedType { private Class c; @@ -70,45 +210,42 @@ public class Compiler { final static class LoadedField implements IBinaryField { private Field f; - LoadedField(Field f) { this.f = f; } - public Constant getConstant() { return Constant.NotAConstant; }// FIXME - public char[] getTypeName() { return typeName(f.getType()); } - public char[] getName() { return f.getName().toCharArray(); } - public int getModifiers() { return f.getModifiers(); } - } + private Constant c; - private static char[] typeName(Class p) { - StringBuffer sb = new StringBuffer(); - typeName(p, sb); - return sb.toString().toCharArray(); - } - private static void typeName(Class p, StringBuffer sb) { - String name = p.getName(); - switch (name.charAt(0)) { - case 'B': case 'C': case 'D': case 'F': case 'I': - case 'J': case 'S': case 'Z': case 'V': case '[': - sb.append(name); break; + LoadedField(Field f) { + this.f = f; + int m = f.getModifiers(); - case 'b': if (name.equals("boolean")) { sb.append('Z'); break; } - if (name.equals("byte")) { sb.append('B'); break; } - case 'c': if (name.equals("char")) { sb.append('C'); break; } - case 'd': if (name.equals("double")) { sb.append('D'); break; } - case 'f': if (name.equals("float")) { sb.append('F'); break; } - case 'i': if (name.equals("int")) { sb.append('I'); break; } - case 'l': if (name.equals("long")) { sb.append('J'); break; } - case 's': if (name.equals("short")) { sb.append('S'); break; } - case 'v': if (name.equals("void")) { sb.append('V'); break; } - default: - sb.append('L'); sb.append(name(p)); sb.append(';'); + c = Constant.NotAConstant; + if (Modifier.isFinal(m) && Modifier.isStatic(m)) { + try { + Class type = f.getType(); + if (type == Boolean.TYPE) { + c = new BooleanConstant(f.getBoolean(null)); + } else if (type == Byte.TYPE) { + c = new ByteConstant(f.getByte(null)); + } else if (type == Character.TYPE) { + c = new CharConstant(f.getChar(null)); + } else if (type == Double.TYPE) { + c = new DoubleConstant(f.getDouble(null)); + } else if (type == Float.TYPE) { + c = new FloatConstant(f.getFloat(null)); + } else if (type == Integer.TYPE) { + c = new IntConstant(f.getInt(null)); + } else if (type == Long.TYPE) { + c = new LongConstant(f.getLong(null)); + } else if (type == Short.TYPE) { + c = new ShortConstant(f.getShort(null)); + } else if (type == String.class) { + c = new StringConstant((String)f.get(null)); + } + } catch (IllegalAccessException e) {} + } } - } - private static char[] descriptor(Class[] p, Class r) { - StringBuffer sb = new StringBuffer(); - sb.append('('); - if (p != null) for (int i=0; i < p.length; i++) typeName(p[i], sb); - sb.append(')'); - if (r != null) typeName(r, sb); - return sb.toString().toCharArray(); + public Constant getConstant() { return c; } + public char[] getTypeName() { return typeName(f.getType()); } + public char[] getName() { return f.getName().toCharArray(); } + public int getModifiers() { return f.getModifiers(); } } final static class LoadedConstructor implements IBinaryMethod { @@ -152,7 +289,7 @@ public class Compiler { public char[] getSelector() { return m.getName().toCharArray(); } public boolean isConstructor() { return false; } public boolean isClinit() { return false; } - public char[][] getArgumentNames() { return null; } // FIXME: does this do anything cool? + public char[][] getArgumentNames() { return null; } // FEATURE: does this do anything cool? public char[][] getExceptionTypeNames() { return ex; } public char[] getMethodDescriptor() { return desc; } } @@ -210,19 +347,35 @@ public class Compiler { public boolean isMember() { return false; } // FIXME public char[] sourceFileName() { return null; } public char[] getFileName() { return null; } + + public boolean equals(Object o) { + return o == this || super.equals(o) || + (o != null && o instanceof LoadedClass && + c.equals(((LoadedClass)o).c)); + } } - private final INameEnvironment env = new INameEnvironment() { + // Compiler Parameters //////////////////////////////////////////////////// + + /** Used by compiler to resolve classes. */ + final INameEnvironment env = new INameEnvironment() { public NameEnvironmentAnswer findType(char[][] c) { return findType(name(c), pack(c)); } public NameEnvironmentAnswer findType(char[] n, char[][] p) { + if (DEBUG) System.out.println("requesting: "+ str(p, '.') + "."+new String(n)); + try { Class c = Class.forName(str(p, '.') + '.' + new String(n)); + if (DEBUG) System.out.println("found class: "+ c); IBinaryType b = (IBinaryType)loaded.get(c); if (b == null) loaded.put(c, b = new LoadedClass(c)); + if (DEBUG) System.out.println("returning "+b+", name="+new String(b.getName())); return new NameEnvironmentAnswer(b); } catch (ClassNotFoundException e) {} + // cut out searches for java.* packages in sources list + if (p.length > 0 && eq(p[0], "java".toCharArray())) return null; + try { for (int i=0; i < sources.length; i++) if (eq(n, sources[i].n) && eq(p, sources[i].p)) @@ -231,7 +384,7 @@ public class Compiler { new NameEnvironmentAnswer(new ClassFileReader(sources[i].compiled, sources[i].orig.getName().toCharArray(), true)); } catch (ClassFormatException e) { - System.out.println("FIXME unexpected ClassFormatException"); + System.out.println("Unexpected ClassFormatException"); // FIXME e.printStackTrace(); } return null; @@ -242,14 +395,16 @@ public class Compiler { if (eq(name, sources[i].n) && eq(parent, sources[i].p)) return false; return loader.getResource(parentName + ".class") == null && - loader.getResource(parentName + '/' + name + ".class") == null; + loader.getResource(parentName + '/' + new String(name) + ".class") == null; } public void cleanup() {} }; + /** Used by compiler to decide what do with problems.. */ private final IErrorHandlingPolicy policy = DefaultErrorHandlingPolicies.proceedWithAllProblems(); + /** Used by compiler for general options. */ private final Map settings = new HashMap(); { settings.put(CompilerOptions.OPTION_LineNumberAttribute, CompilerOptions.GENERATE); @@ -258,92 +413,58 @@ public class Compiler { settings.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_1); }; + /** Used by compiler for processing compiled classes and their errors. */ private final ICompilerRequestor results = new ICompilerRequestor() { public void acceptResult(CompilationResult result) { + if (DEBUG) System.out.println("got result: "+result); if (result.hasProblems()) { boolean hasErrors = false; IProblem[] p = result.getProblems(); - try { - for (int i=0; i < p.length; i++) { - if (p[i].isError()) hasErrors = true; - out.write(p[i].getOriginatingFileName()); - out.write(':'); - out.write(p[i].getSourceLineNumber()); - out.write(':'); - out.write(p[i].getMessage()); - } - } catch (IOException e) { - System.out.println("FIXME severe: IOException on out"); - e.printStackTrace(); + for (int i=0; i < p.length; i++) { + if (p[i].isError()) hasErrors = true; + out.print(p[i].getOriginatingFileName()); + out.print(':'); + out.print(p[i].getSourceLineNumber()); + out.print(':'); + out.println(p[i].getMessage()); } + out.flush(); if (hasErrors) return; } ClassFile[] c = result.getClassFiles(); for (int i=0; i < c.length; i++) { try { - String name = str(c[i].getCompoundName(), '/') + ".class"; + // build package path to new class file + File path = builddir; + char[][] name = c[i].getCompoundName(); + path = new File(builddir, str(pack(name), '/')); + if (DEBUG) System.out.println("DEBUG: creating path "+path+", out of builddir="+builddir); + if (!path.exists()) path.mkdirs(); + + // write new class file + path = new File(path, new String(name(name)) + ".class"); + if (DEBUG) System.out.println("DEBUG: writing file "+path); OutputStream o = new BufferedOutputStream( - new FileOutputStream(new File(name))); + new FileOutputStream(path)); o.write(c[i].getBytes()); o.close(); } catch (IOException e) { - System.out.println("FIXME: IOException writing class"); + System.out.println("IOException writing class"); // FIXME e.printStackTrace(); } } } }; + /** Problem creater for compiler. */ private final IProblemFactory problems = new DefaultProblemFactory(); - private final class Source { - char[] n; char[][] p; - File orig; - char[] processed = null; - byte[] compiled = null; - - ICompilationUnit unit = new ICompilationUnit() { - public char[] getMainTypeName() { return n; } - public char[][] getPackageName() { return p; } - public char[] getFileName() { return orig.getName().toCharArray(); } - public char[] getContents() { - if (processed != null) return processed; - - try { - Reader r = new InputStreamReader(new BufferedInputStream( - new FileInputStream(orig))); - StringWriter w = new StringWriter(); - Vector err; - - synchronized (preprocessor) { - preprocessor.setReader(r); - preprocessor.setWriter(w); - err = preprocessor.process(); - } - - if (err.size() > 0) { - System.out.println("Preprocessor Errors, "+err); // FIXME - return null; - } - - processed = w.toString().toCharArray(); - } catch (IOException e) { - System.out.println("FIXME: IOException: "+e); // FIXME - return null; - } - - return processed; - } - }; - - private Source(File o, char[] n, char[][] p) { - orig = o; this.n = n; this.p = p; } - } // Helper Functiosn /////////////////////////////////////////////////////// - /** Convert source file path into class name. */ + /** Convert source file path into class name block. + * eg. in: java/lang/String.java -> { {java} {lang} {String} } */ private char[][] classname(String name) { String delim = name.indexOf('/') == -1 ? "." : "/"; name = name.trim(); @@ -356,35 +477,87 @@ public class Compiler { return n; } + /** Convert class name into a String. */ private static String str(char[][] name, char delim) { StringBuffer b = new StringBuffer(); - if (name != null) for (int i=0; i < name.length; i++) - if (name[i] != null) { b.append(delim); b.append(name[i]); } - if (b.length() > 0) b.deleteCharAt(0); + for (int i=0; name != null && i < name.length; i++) { + if (name[i] == null || name[i].length == 0) continue; + if (i > 0) b.append(delim); + b.append(name[i]); + } return b.toString(); } + /** Returns the package component of a class name. + * Effectively returns char[length - 1][]. */ private static char[][] pack(char[][] c) { char[][] p = new char[c.length - 1][]; for (int i=0; i < p.length; i++) p[i] = c[i]; return p; } + /** Returns the direct-name component of a class name. + * eg. String from java.lang.String */ private static char[] name(char[][] c) { return c[c.length - 1]; } + /** Returns true of contents of both char arrays are equal. */ private static boolean eq(char[][] c1, char[][] c2) { if (c1.length != c2.length) return false; for (int i=0; i < c1.length; i++) if (!eq(c1[i], c2[i])) return false; return true; } + /** Returns true of contents of both char arrays are equal. */ private static boolean eq(char[] c1, char[] c2) { if (c1.length != c2.length) return false; for (int i=0; i < c1.length; i++) if (c1[i] != c2[i]) return false; return true; } + /** Returns class name as per VM Spec 4.2. eg. java/lang/String */ private static char[] name(Class c) { return c == null ? null : c.getName().replace('.', '/').toCharArray(); } + + /** Returns the type name of a class as per VM Spec 4.3.2. */ + private static char[] typeName(Class p) { + StringBuffer sb = new StringBuffer(); + typeName(p, sb); + return sb.toString().toCharArray(); + } + + /** Returns the type name of a class as per VM Spec 4.3.2. + * eg. int -> I, String -> Ljava/lang/String; */ + private static void typeName(Class p, StringBuffer sb) { + String name = p.getName(); + switch (name.charAt(0)) { + case 'B': case 'C': case 'D': case 'F': case 'I': + case 'J': case 'S': case 'Z': case 'V': case '[': + sb.append(name(p)); break; + + case 'b': if (name.equals("boolean")) { sb.append('Z'); break; } + if (name.equals("byte")) { sb.append('B'); break; } + case 'c': if (name.equals("char")) { sb.append('C'); break; } + case 'd': if (name.equals("double")) { sb.append('D'); break; } + case 'f': if (name.equals("float")) { sb.append('F'); break; } + case 'i': if (name.equals("int")) { sb.append('I'); break; } + case 'l': if (name.equals("long")) { sb.append('J'); break; } + case 's': if (name.equals("short")) { sb.append('S'); break; } + case 'v': if (name.equals("void")) { sb.append('V'); break; } + default: + sb.append('L'); sb.append(name(p)); sb.append(';'); + } + } + + /** Returns the descriptor of a method per VM Spec 4.3.3. + * eg. int get(String n, boolean b) -> (Ljava/lang/String;B)I */ + private static char[] descriptor(Class[] p, Class r) { + StringBuffer sb = new StringBuffer(); + sb.append('('); + if (p != null) for (int i=0; i < p.length; i++) typeName(p[i], sb); + sb.append(')'); + if (r != null) typeName(r, sb); + return sb.toString().toCharArray(); + } + }