From b39ea7a876cfd4af6f06b82c50a373e7d0488f69 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Mon, 31 Oct 2011 13:35:18 +0100 Subject: [PATCH] module compiler: initial working version --- build.xml | 1 + .../jet/codegen/GeneratedClassLoader.java | 23 +++++ compiler/cli/cli.iml | 1 + .../org/jetbrains/jet/cli/KotlinCompiler.java | 91 ++++++++++++++++--- .../jet/codegen/CodegenTestCase.java | 21 +---- stdlib/ktSrc/ModuleBuilder.kt | 8 +- stdlib/src/jet/modules/IModuleBuilder.java | 1 + stdlib/src/jet/modules/IModuleSetBuilder.java | 10 ++ 8 files changed, 121 insertions(+), 35 deletions(-) create mode 100644 compiler/backend/src/org/jetbrains/jet/codegen/GeneratedClassLoader.java create mode 100644 stdlib/src/jet/modules/IModuleSetBuilder.java diff --git a/build.xml b/build.xml index c5a74ee9208..bc0ee63e9f7 100644 --- a/build.xml +++ b/build.xml @@ -29,6 +29,7 @@ + diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/GeneratedClassLoader.java b/compiler/backend/src/org/jetbrains/jet/codegen/GeneratedClassLoader.java new file mode 100644 index 00000000000..b851b21a8a0 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/GeneratedClassLoader.java @@ -0,0 +1,23 @@ +package org.jetbrains.jet.codegen; + +/** +* @author yole +*/ +public class GeneratedClassLoader extends ClassLoader { + private final ClassFileFactory state; + + public GeneratedClassLoader(ClassFileFactory state) { + super(GeneratedClassLoader.class.getClassLoader()); + this.state = state; + } + + @Override + protected Class findClass(String name) throws ClassNotFoundException { + String file = name.replace('.', '/') + ".class"; + if (state.files().contains(file)) { + byte[] bytes = state.asBytes(file); + return defineClass(name, bytes, 0, bytes.length); + } + return super.findClass(name); + } +} diff --git a/compiler/cli/cli.iml b/compiler/cli/cli.iml index de82ce75e19..ed2341d3d46 100644 --- a/compiler/cli/cli.iml +++ b/compiler/cli/cli.iml @@ -10,6 +10,7 @@ + diff --git a/compiler/cli/src/org/jetbrains/jet/cli/KotlinCompiler.java b/compiler/cli/src/org/jetbrains/jet/cli/KotlinCompiler.java index e391db30564..7f047272fe2 100644 --- a/compiler/cli/src/org/jetbrains/jet/cli/KotlinCompiler.java +++ b/compiler/cli/src/org/jetbrains/jet/cli/KotlinCompiler.java @@ -2,14 +2,16 @@ package org.jetbrains.jet.cli; import com.intellij.openapi.Disposable; import com.intellij.openapi.application.PathManager; -import com.intellij.openapi.roots.FileIndexFacade; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.Processor; import com.sampullara.cli.Args; import com.sampullara.cli.Argument; +import jet.modules.IModuleBuilder; +import jet.modules.IModuleSetBuilder; import org.jetbrains.jet.JetCoreEnvironment; import org.jetbrains.jet.codegen.ClassFileFactory; +import org.jetbrains.jet.codegen.GeneratedClassLoader; import org.jetbrains.jet.lang.psi.JetNamespace; import org.jetbrains.jet.plugin.JetMainDetector; @@ -17,6 +19,7 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; +import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; import java.util.List; @@ -66,9 +69,19 @@ public class KotlinCompiler { if (unpackedRuntimePath != null) { environment.addToClasspath(unpackedRuntimePath); } + else { + final File runtimeJarPath = getRuntimeJarPath(); + if (runtimeJarPath != null && runtimeJarPath.exists()) { + environment.addToClasspath(runtimeJarPath); + } + else { + System.out.println("No runtime library found"); + return; + } + } if (arguments.module != null) { - compileModule(environment, arguments.module); + compileModuleScript(environment, arguments.module); return; } @@ -98,30 +111,82 @@ public class KotlinCompiler { } } - private static void compileModule(JetCoreEnvironment environment, String moduleFile) { - final FileIndexFacade instance = FileIndexFacade.getInstance(environment.getProject()); - VirtualFile jetObject = environment.getLocalFileSystem().findFileByPath(KotlinCompiler.class.getClassLoader().getResource("jet/JetObject.class").getPath()); - instance.isInLibraryClasses(jetObject); - - CompileSession moduleCompileSession = new CompileSession(environment); - moduleCompileSession.addSources(moduleFile); + private static void compileModuleScript(JetCoreEnvironment environment, String moduleFile) { + CompileSession scriptCompileSession = new CompileSession(environment); + scriptCompileSession.addSources(moduleFile); URL url = KotlinCompiler.class.getClassLoader().getResource("ModuleBuilder.kt"); if (url != null) { - // TODO + String path = url.getPath(); + if (path.startsWith("file:")) { + path = path.substring(5); + } + final VirtualFile vFile = environment.getJarFileSystem().findFileByPath(path); + if (vFile == null) { + System.out.println("Couldn't load ModuleBuilder.kt from runtime jar: "+ url); + return; + } + scriptCompileSession.addSources(vFile); } else { // building from source final String homeDirectory = getHomeDirectory(); final File file = new File(homeDirectory, "stdlib/ktSrc/ModuleBuilder.kt"); - moduleCompileSession.addSources(environment.getLocalFileSystem().findFileByPath(file.getPath())); - + scriptCompileSession.addSources(environment.getLocalFileSystem().findFileByPath(file.getPath())); } + if (!scriptCompileSession.analyze()) { + return; + } + final ClassFileFactory factory = scriptCompileSession.generate(); + + final IModuleSetBuilder moduleSetBuilder = runDefineModules(moduleFile, factory); + + for (IModuleBuilder moduleBuilder : moduleSetBuilder.getModules()) { + compileModule(environment, moduleBuilder, new File(moduleFile).getParent()); + } + } + + private static IModuleSetBuilder runDefineModules(String moduleFile, ClassFileFactory factory) { + GeneratedClassLoader loader = new GeneratedClassLoader(factory); + try { + Class moduleSetBuilderClass = loader.loadClass("kotlin.modules.ModuleSetBuilder"); + final IModuleSetBuilder moduleSetBuilder = (IModuleSetBuilder) moduleSetBuilderClass.newInstance(); + + Class namespaceClass = loader.loadClass("namespace"); + final Method[] methods = namespaceClass.getMethods(); + boolean modulesDefined = false; + for (Method method : methods) { + if (method.getName().equals("defineModules")) { + method.invoke(null, moduleSetBuilder); + modulesDefined = true; + break; + } + } + if (!modulesDefined) { + System.out.println("Module script " + moduleFile + " must define a defineModules() method"); + return null; + } + return moduleSetBuilder; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + private static void compileModule(JetCoreEnvironment environment, IModuleBuilder moduleBuilder, String directory) { + CompileSession moduleCompileSession = new CompileSession(environment); + for (String sourceFile : moduleBuilder.getSourceFiles()) { + moduleCompileSession.addSources(new File(directory, sourceFile).getPath()); + } + for (String classpathRoot : moduleBuilder.getClasspathRoots()) { + environment.addToClasspath(new File(classpathRoot)); + } if (!moduleCompileSession.analyze()) { return; } - final ClassFileFactory factory = moduleCompileSession.generate(); + ClassFileFactory factory = moduleCompileSession.generate(); + writeToJar(factory, new File(directory, moduleBuilder.getModuleName() + ".jar").getPath(), null, true); } private static String getHomeDirectory() { diff --git a/compiler/tests/org/jetbrains/jet/codegen/CodegenTestCase.java b/compiler/tests/org/jetbrains/jet/codegen/CodegenTestCase.java index 8b0bb54a270..e6ec1009270 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/CodegenTestCase.java +++ b/compiler/tests/org/jetbrains/jet/codegen/CodegenTestCase.java @@ -88,7 +88,7 @@ public abstract class CodegenTestCase extends JetLiteFixture { protected String blackBox() throws Exception { ClassFileFactory codegens = generateClassesInFile(); - CodegensClassLoader loader = new CodegensClassLoader(codegens); + GeneratedClassLoader loader = new GeneratedClassLoader(codegens); final JetNamespace namespace = myFile.getRootNamespace(); String fqName = NamespaceCodegen.getJVMClassName(namespace.getFQName()).replace("/", "."); @@ -215,23 +215,4 @@ public abstract class CodegenTestCase extends JetLiteFixture { return super.loadClass(name); } } - - private static class CodegensClassLoader extends ClassLoader { - private final ClassFileFactory state; - - public CodegensClassLoader(ClassFileFactory state) { - super(CodegenTestCase.class.getClassLoader()); - this.state = state; - } - - @Override - protected Class findClass(String name) throws ClassNotFoundException { - String file = name.replace('.', '/') + ".class"; - if (state.files().contains(file)) { - byte[] bytes = state.asBytes(file); - return defineClass(name, bytes, 0, bytes.length); - } - return super.findClass(name); - } - } } diff --git a/stdlib/ktSrc/ModuleBuilder.kt b/stdlib/ktSrc/ModuleBuilder.kt index 2f90dcb1158..7e2e25e8715 100644 --- a/stdlib/ktSrc/ModuleBuilder.kt +++ b/stdlib/ktSrc/ModuleBuilder.kt @@ -5,13 +5,16 @@ namespace modules { import java.util.* import jet.modules.* -class ModuleSetBuilder() { - val modules: ArrayList = ArrayList() +class ModuleSetBuilder(): IModuleSetBuilder { + val modules: ArrayList = ArrayList() fun module(name: String, callback: fun ModuleBuilder.()) { val builder = ModuleBuilder(name) builder.callback() + modules.add(builder) } + + override fun getModules(): List? = modules } class SourcesBuilder(val parent: ModuleBuilder) { @@ -46,6 +49,7 @@ class ModuleBuilder(val name: String): IModuleBuilder { override fun getSourceFiles(): List? = sourceFiles override fun getClasspathRoots(): List? = classpathRoots + override fun getModuleName(): String? = name } } \ No newline at end of file diff --git a/stdlib/src/jet/modules/IModuleBuilder.java b/stdlib/src/jet/modules/IModuleBuilder.java index 53ac51123c6..c845e04a021 100644 --- a/stdlib/src/jet/modules/IModuleBuilder.java +++ b/stdlib/src/jet/modules/IModuleBuilder.java @@ -6,6 +6,7 @@ import java.util.List; * @author yole */ public interface IModuleBuilder { + String getModuleName(); List getSourceFiles(); List getClasspathRoots(); } diff --git a/stdlib/src/jet/modules/IModuleSetBuilder.java b/stdlib/src/jet/modules/IModuleSetBuilder.java new file mode 100644 index 00000000000..7f5f03dc3d2 --- /dev/null +++ b/stdlib/src/jet/modules/IModuleSetBuilder.java @@ -0,0 +1,10 @@ +package jet.modules; + +import java.util.List; + +/** + * @author yole + */ +public interface IModuleSetBuilder { + List getModules(); +}