summaryrefslogtreecommitdiff
path: root/src/main/java/io/devnulllabs/openjava/ojc/Compiler.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/io/devnulllabs/openjava/ojc/Compiler.java')
-rw-r--r--src/main/java/io/devnulllabs/openjava/ojc/Compiler.java569
1 files changed, 569 insertions, 0 deletions
diff --git a/src/main/java/io/devnulllabs/openjava/ojc/Compiler.java b/src/main/java/io/devnulllabs/openjava/ojc/Compiler.java
new file mode 100644
index 0000000..6e3abe5
--- /dev/null
+++ b/src/main/java/io/devnulllabs/openjava/ojc/Compiler.java
@@ -0,0 +1,569 @@
+/*
+ * Compiler.java
+ *
+ *
+ */
+package io.devnulllabs.openjava.ojc;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.lang.reflect.Constructor;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.StringTokenizer;
+
+import io.devnulllabs.openjava.mop.Environment;
+import io.devnulllabs.openjava.mop.FileEnvironment;
+import io.devnulllabs.openjava.mop.MetaInfo;
+import io.devnulllabs.openjava.mop.OJClass;
+import io.devnulllabs.openjava.mop.OJClassNotFoundException;
+import io.devnulllabs.openjava.mop.OJSystem;
+import io.devnulllabs.openjava.ptree.ClassDeclaration;
+import io.devnulllabs.openjava.ptree.ClassDeclarationList;
+import io.devnulllabs.openjava.ptree.CompilationUnit;
+import io.devnulllabs.openjava.ptree.ParseTreeException;
+import io.devnulllabs.openjava.ptree.util.ExpansionApplier;
+import io.devnulllabs.openjava.ptree.util.MemberAccessCorrector;
+import io.devnulllabs.openjava.ptree.util.SourceCodeWriter;
+import io.devnulllabs.openjava.ptree.util.TypeNameQualifier;
+import io.devnulllabs.openjava.tools.DebugOut;
+import io.devnulllabs.openjava.tools.parser.ParseException;
+import io.devnulllabs.openjava.tools.parser.Parser;
+
+public class Compiler {
+ final CommandArguments arguments;
+ final File files[];
+ final FileEnvironment[] file_env;
+ final CompilationUnit[] comp_unit;
+
+ JavaCompiler java_compiler;
+ CompilationUnit[] added_cu = null;
+
+ Compiler(CommandArguments arguments) {
+ super();
+ this.arguments = arguments;
+ this.files = arguments.getFiles();
+ this.file_env = new FileEnvironment[files.length];
+ this.comp_unit = new CompilationUnit[files.length];
+
+ DebugOut.setDebugLevel(arguments.getDebugLevel());
+ initPrimitiveTypes();
+ try {
+ this.java_compiler = arguments.getJavaCompiler();
+ OJSystem.setJavaCompiler(this.java_compiler);
+ } catch (Exception e) {
+ System.err.println("illegal java compiler : " + e);
+ }
+ }
+
+ public void run() {
+ try {
+ configSpecifiedMetaBind();
+ } catch (Exception e) {
+ System.err.println(e);
+ }
+
+ initFileEnv();
+
+ System.err.println("Generating parse tree.");
+ generateParseTree();
+ System.err.println("..done.");
+
+ System.err.println("Initializing parse tree.");
+ initParseTree();
+ System.err.println("..done.");
+
+ System.err.println("Translating callee side");
+ translateCalleeSide();
+ System.err.println("..done.");
+
+ System.err.println("Translating caller side");
+ if (arguments.callerTranslation()) {
+ translateCallerSide();
+ System.err.println("..done.");
+ } else {
+ System.err.println("..skipped.");
+ }
+
+ generateAdditionalCompilationUnit();
+
+ System.err.println("Printing parse tree.");
+ outputToFile();
+ System.err.println("..done.");
+
+ System.err.println("Compiling into bytecode.");
+ javac();
+ System.err.println("..done.");
+
+ System.err.flush();
+ }
+
+ void configSpecifiedMetaBind() throws Exception {
+ String[] cfile = arguments.getOptions("-default-meta");
+ for (int i = 0; i < cfile.length; ++i) {
+ BufferedReader reader =
+ new BufferedReader(new FileReader(cfile[i]));
+ String line;
+ while ((line = reader.readLine()) != null) {
+ StringTokenizer tokenizer = new StringTokenizer(line);
+ try {
+ String mclazz = tokenizer.nextToken();
+ String bclazz = tokenizer.nextToken();
+ OJSystem.metabind(bclazz, mclazz);
+ } catch (java.util.NoSuchElementException e) {
+ /** ignore this line */
+ }
+ }
+ reader.close();
+ }
+ }
+
+ void initFileEnv() {
+ for (int i = 0; i < files.length; ++i) {
+ file_env[i] =
+ new FileEnvironment(OJSystem.env, null, null, files[i]);
+ }
+ }
+
+ void generateParseTree() {
+ for (int i = 0; i < files.length; ++i) {
+ DebugOut.println("parsing file " + files[i]);
+ try {
+ comp_unit[i] = parse(files[i]);
+ file_env[i].setCompilationUnit(comp_unit[i]);
+
+ ClassDeclarationList typedecls =
+ comp_unit[i].getClassDeclarations();
+ for (int j = 0; j < typedecls.size(); ++j) {
+ ClassDeclaration clazz_decl = typedecls.get(j);
+ /***********************************************************
+ * this may be ambiguos. there's OJClass.forParseTree()
+ */
+ OJClass c = makeOJClass(file_env[i], clazz_decl);
+ if (c.getModifiers().isPublic()) {
+ /* public/main class */
+ DebugOut.println("main class " + c.getName());
+ } else {
+ /* non-public class */
+ DebugOut.println("local class " + c.getName());
+ }
+ OJSystem.env.record(c.getName(), c);
+ /** * should consider private * */
+ recordInnerClasses(c);
+ }
+ } catch (Exception ex) {
+ System.err.println("errors during parsing. " + ex);
+ ex.printStackTrace();
+ }
+ DebugOut.println("file environment : ");
+ DebugOut.println(file_env[i]);
+ }
+
+ DebugOut.println("global environment : ");
+ DebugOut.println(OJSystem.env);
+ }
+
+ private static void recordInnerClasses(OJClass c) {
+ OJClass[] inners = c.getDeclaredClasses();
+ for (int i = 0; i < inners.length; ++i) {
+ OJSystem.env.record(inners[i].getName(), inners[i]);
+ recordInnerClasses(inners[i]);
+ }
+ }
+
+ void generateAdditionalCompilationUnit() {
+ OJClass[] added = OJSystem.addedClasses();
+ this.added_cu = new CompilationUnit[added.length];
+ for (int i = 0; i < added.length; ++i) {
+ ClassDeclarationList cdecls;
+ try {
+ cdecls = new ClassDeclarationList(added[i].getSourceCode());
+ } catch (Exception e) {
+ System.err.println("errors during generating " + added[i]);
+ e.printStackTrace();
+ continue;
+ }
+ String pack = added[i].getPackage();
+ added_cu[i] = new CompilationUnit(pack, null, cdecls);
+ }
+ }
+
+ /** -> to move to OJClass.forParseTree() * */
+ private OJClass makeOJClass(Environment env, ClassDeclaration cdecl) {
+ OJClass result;
+ String qname = env.toQualifiedName(cdecl.getName());
+ Class meta = OJSystem.getMetabind(qname);
+ try {
+ Constructor constr =
+ meta.getConstructor(
+ new Class[] {
+ Environment.class,
+ OJClass.class,
+ ClassDeclaration.class });
+ Object[] args = new Object[] { env, null, cdecl };
+ result = (OJClass) constr.newInstance(args);
+ } catch (Exception ex) {
+ System.err.println(
+ "errors during gererating a metaobject for " + qname);
+ ex.printStackTrace();
+ result = new OJClass(env, null, cdecl);
+ }
+
+ return result;
+ }
+
+ void initDebug() {
+ }
+
+ void outputToFile() {
+ for (int i = 0; i < comp_unit.length; ++i) {
+ if (comp_unit[i] == null)
+ continue;
+
+ File outfile = null;
+ try {
+ outfile =
+ getOutputFile(files[i], file_env[i], comp_unit[i], ".java");
+ FileWriter fout = new FileWriter(outfile);
+ PrintWriter out = new PrintWriter(fout);
+ SourceCodeWriter writer = new SourceCodeWriter(out);
+ writer.setDebugLevel(0);
+ comp_unit[i].accept(writer);
+ out.flush();
+ out.close();
+ } catch (IOException e) {
+ System.err.println("fails to create " + outfile);
+ } catch (ParseTreeException e) {
+ System.err.println("errors during printing " + outfile);
+ e.printStackTrace();
+ }
+
+ try {
+ outfile =
+ getOutputFile(
+ files[i],
+ null,
+ comp_unit[i],
+ MetaInfo.SUFFIX + ".java");
+ String qname = file_env[i].toQualifiedName(baseName(files[i]));
+ OJClass clazz = OJClass.forName(qname);
+ FileWriter fout = new FileWriter(outfile);
+ clazz.writeMetaInfo(fout);
+ fout.flush();
+ fout.close();
+ } catch (OJClassNotFoundException e) {
+ //System.err.println("The class object not found for " +
+ // outfile);
+ } catch (IOException e) {
+ System.err.println("fails to create " + outfile);
+ } catch (ParseTreeException e) {
+ System.err.println("errors during printing " + outfile);
+ e.printStackTrace();
+ }
+ }
+
+ for (int i = 0; i < added_cu.length; ++i) {
+ File outfile = null;
+ try {
+ outfile = getOutputFile(null, null, added_cu[i], ".java");
+ FileWriter fout = new FileWriter(outfile);
+ PrintWriter out = new PrintWriter(fout);
+ SourceCodeWriter writer = new SourceCodeWriter(out);
+ writer.setDebugLevel(0);
+ added_cu[i].accept(writer);
+ out.flush();
+ out.close();
+ } catch (IOException e) {
+ System.err.println("fails to create " + outfile);
+ } catch (ParseTreeException e) {
+ System.err.println("errors during printing " + outfile);
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private static final String class2path(String cname) {
+ return cname.replace('.', File.separatorChar);
+ }
+
+ private static final String unknownClassName = "OJ_Unknown";
+ private static int nonpubclassid = 0;
+ private File getOutputFile(
+ File fin,
+ FileEnvironment file_env,
+ CompilationUnit comp_unit,
+ String suffix)
+ throws ParseTreeException {
+ String pack = comp_unit.getPackage();
+ String sname;
+ ClassDeclaration cd = comp_unit.getPublicClass();
+ if (cd != null) {
+ sname = cd.getName();
+ } else if (file_env != null) {
+ String path = file_env.getFile().getPath();
+ int suffix_index = path.lastIndexOf('.');
+ String javaPath = path.substring(0, suffix_index) + suffix;
+ return new File(javaPath);
+ } else {
+ sname = unknownClassName + nonpubclassid++;
+ }
+ return getOutputFile(fin, pack, sname, suffix);
+ }
+
+ private File getOutputFile(
+ File fin,
+ String pack,
+ String name,
+ String suffix) {
+ File dir; /* directory to put the file in */
+ String distbase = arguments.getOption("d");
+ if (distbase == null && fin != null) {
+ /* the same directory where source file is */
+ String dirname = fin.getParent();
+ if (dirname == null)
+ dirname = ".";
+ dir = new File(dirname);
+ } else {
+ if (distbase == null)
+ distbase = ".";
+ File basedir = new File(distbase);
+ if (pack == null || pack.equals("")) {
+ dir = basedir;
+ } else {
+ dir = new File(basedir, class2path(pack));
+ if ((!dir.isDirectory()) && (!dir.mkdirs())) {
+ System.err.println("fail to create dir : " + dir);
+ dir = new File(".");
+ }
+ }
+ }
+ return new File(dir, name + suffix);
+ }
+
+ private static String baseName(File file) {
+ String name = file.getName();
+ int index = name.lastIndexOf('.');
+ if (index == -1)
+ return name;
+ return name.substring(0, index);
+ }
+
+ void initParseTree() {
+ for (int i = 0; i < comp_unit.length; ++i) {
+ if (comp_unit[i] == null) {
+ System.err.println(files[i] + " is skipped.");
+ continue;
+ }
+ try {
+ if (arguments.callerTranslation()
+ && arguments.qualifyNameFirst()) {
+ comp_unit[i].accept(new TypeNameQualifier(file_env[i]));
+ }
+ MemberAccessCorrector corrector =
+ new MemberAccessCorrector(file_env[i]);
+ comp_unit[i].accept(corrector);
+ } catch (ParseTreeException e) {
+ System.err.println("Encountered errors during analysis.");
+ e.printStackTrace();
+ }
+ }
+ }
+
+ void translateCalleeSide() {
+ Hashtable under_c = OJSystem.underConstruction;
+ for (int i = 0; i < comp_unit.length; ++i) {
+ if (comp_unit[i] == null) {
+ System.err.println(files[i] + " is skipped.");
+ continue;
+ }
+ ClassDeclarationList cdecls = comp_unit[i].getClassDeclarations();
+ for (int j = 0; j < cdecls.size(); ++j) {
+ ClassDeclaration cdecl = cdecls.get(j);
+ String qname = file_env[i].toQualifiedName(cdecl.getName());
+ OJClass clazz;
+ try {
+ clazz = OJClass.forName(qname);
+ } catch (OJClassNotFoundException ex) {
+ System.err.println("no " + qname + " : " + ex);
+ return;
+ }
+ translateClassDecls(under_c, clazz, file_env[i]);
+ }
+ }
+
+ try {
+ while (!under_c.isEmpty()) {
+ OJClass clazz = (OJClass) under_c.keys().nextElement();
+ resolveOrder(clazz);
+ }
+ } catch (InterruptedException e) {
+ System.err.println("translation failed : " + e);
+ }
+ }
+
+ private void translateClassDecls(
+ Hashtable table,
+ OJClass clazz,
+ Environment env) {
+ table.put(clazz, new TranslatorThread(env, clazz));
+
+ OJClass[] inners = clazz.getDeclaredClasses();
+ for (int i = 0; i < inners.length; ++i) {
+ translateClassDecls(table, inners[i], clazz.getEnvironment());
+ }
+ }
+
+ private void resolveOrder(OJClass clazz) throws InterruptedException {
+ /* lock for the given class metaobject */
+ Object lock = new Object();
+ Hashtable under_c = OJSystem.underConstruction;
+
+ synchronized (clazz) {
+ OJSystem.orderingLock = lock;
+ ((TranslatorThread) under_c.get(clazz)).start();
+
+ /*
+ * wait until the translation of the class is suspended or
+ * finished.
+ */
+ clazz.wait();
+ }
+
+ /*
+ * OJSystem.waited is set to null if the translation is finished.
+ * Otherwise the translation needs the translation of the class set in
+ * OJSystem.waited. It can be suspended for several times.
+ */
+ while (OJSystem.waited != null) {
+ resolveOrder(OJSystem.waited);
+
+ synchronized (clazz) {
+ OJSystem.orderingLock = lock;
+ synchronized (lock) {
+ lock.notifyAll();
+ }
+ clazz.wait();
+ }
+ }
+
+ under_c.remove(clazz);
+ }
+
+ void translateCallerSide() {
+ for (int i = 0; i < comp_unit.length; ++i) {
+ if (comp_unit[i] == null) {
+ System.err.println(files[i] + " is skipped.");
+ continue;
+ }
+ try {
+ ExpansionApplier expander = new ExpansionApplier(file_env[i]);
+ comp_unit[i].accept(expander);
+ } catch (ParseTreeException e) {
+ System.err.println(
+ "Encountered errors during translating caller side.");
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private static CompilationUnit parse(File file) {
+ Parser parser;
+
+ try {
+ parser = new Parser(new java.io.FileInputStream(file));
+ } catch (java.io.FileNotFoundException e) {
+ System.err.println("File " + file + " not found.");
+ return null;
+ }
+
+ CompilationUnit result;
+ try {
+ result = parser.CompilationUnit(OJSystem.env);
+ } catch (ParseException e) {
+ System.err.println("Encountered errors during parse.");
+ e.printStackTrace();
+ result = null;
+ }
+
+ return result;
+ }
+
+ private static void initPrimitiveTypes() {
+ OJSystem.initConstants();
+ /*
+ * OJClass.forClass( boolean . class ); OJClass.forClass( byte . class );
+ * OJClass.forClass( char . class ); OJClass.forClass( short . class );
+ * OJClass.forClass( int . class ); OJClass.forClass( long . class );
+ * OJClass.forClass( float . class ); OJClass.forClass( double . class );
+ * OJClass.forClass( void . class );
+ */
+ }
+
+ /**
+ * Compiles the generated files into byte codes
+ */
+ private void javac() {
+ ArrayList argsList = new ArrayList();
+
+ String[] options = arguments.getOptions("C");
+ for (int i = 0; i < options.length; ++i) {
+ argsList.add(options[i]);
+ }
+
+ try {
+ for (int i = 0; i < files.length; ++i) {
+ addCompiledFile(
+ argsList,
+ files[i],
+ file_env[i],
+ comp_unit[i],
+ ".java");
+ addCompiledFile(
+ argsList,
+ files[i],
+ null,
+ comp_unit[i],
+ MetaInfo.SUFFIX + ".java");
+ }
+ for (int i = 0; i < added_cu.length; ++i) {
+ addCompiledFile(argsList, files[i], null, added_cu[i], ".java");
+ addCompiledFile(
+ argsList,
+ files[i],
+ null,
+ added_cu[i],
+ MetaInfo.SUFFIX + ".java");
+ }
+
+ String[] args = new String[argsList.size()];
+ for (int i = 0; i < args.length; ++i) {
+ args[i] = (String) argsList.get(i);
+ }
+
+ java_compiler.compile(args);
+ } catch (Exception e) {
+ System.err.println("errors during compiling into bytecode.");
+ e.printStackTrace();
+ }
+ }
+
+ private void addCompiledFile(
+ ArrayList argsList,
+ File file,
+ FileEnvironment fenv,
+ CompilationUnit cu,
+ String suffix) {
+ try {
+ File javafile = getOutputFile(file, fenv, cu, suffix);
+ if (javafile.exists())
+ argsList.add(javafile.getPath());
+ } catch (ParseTreeException ex) {
+ System.err.println(ex.toString());
+ return;
+ }
+ }
+}