From 4da91ee3d62a02b97aa842a80e5a12601f856f64 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Fri, 20 Apr 2012 11:51:47 +0400 Subject: [PATCH] CompileEnvironment removed What used to be CompileEnvironment, now is split into data (in CompileEnvironmentConfiguration) and utility methods (in CompileEnvironmentUtil). CompilerDependencies should be removed later. All the relevant stuff sits in the JetCoreEnvironment class --- .../jet/buildtools/core/BytecodeCompiler.java | 25 +- .../org/jetbrains/jet/cli/KotlinCompiler.java | 37 +-- .../jet/compiler/CompileEnvironment.java | 243 ------------------ .../CompileEnvironmentConfiguration.java | 56 ++++ .../jet/compiler/CompileEnvironmentUtil.java | 39 ++- .../compiler/KotlinToJVMBytecodeCompiler.java | 172 ++++++++++++- .../jet/codegen/CompileTextTest.java | 14 +- .../org/jetbrains/jet/codegen/StdlibTest.java | 4 +- 8 files changed, 308 insertions(+), 282 deletions(-) delete mode 100644 compiler/cli/src/org/jetbrains/jet/compiler/CompileEnvironment.java create mode 100644 compiler/cli/src/org/jetbrains/jet/compiler/CompileEnvironmentConfiguration.java diff --git a/build-tools/core/src/org/jetbrains/jet/buildtools/core/BytecodeCompiler.java b/build-tools/core/src/org/jetbrains/jet/buildtools/core/BytecodeCompiler.java index c1395d86f5f..f7d78f49cf0 100644 --- a/build-tools/core/src/org/jetbrains/jet/buildtools/core/BytecodeCompiler.java +++ b/build-tools/core/src/org/jetbrains/jet/buildtools/core/BytecodeCompiler.java @@ -18,9 +18,7 @@ package org.jetbrains.jet.buildtools.core; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.compiler.CompileEnvironment; -import org.jetbrains.jet.compiler.CompileEnvironmentException; -import org.jetbrains.jet.compiler.CompilerPlugin; +import org.jetbrains.jet.compiler.*; import org.jetbrains.jet.compiler.messages.MessageCollector; import org.jetbrains.jet.lang.resolve.java.CompilerDependencies; import org.jetbrains.jet.lang.resolve.java.CompilerSpecialMode; @@ -42,22 +40,25 @@ public class BytecodeCompiler { /** - * Creates new instance of {@link CompileEnvironment} instance using the arguments specified. + * Creates new instance of {@link org.jetbrains.jet.compiler.CompileEnvironmentConfiguration} instance using the arguments specified. * * @param stdlib path to "kotlin-runtime.jar", only used if not null and not empty * @param classpath compilation classpath, only used if not null and not empty * * @return compile environment instance */ - private CompileEnvironment env( String stdlib, String[] classpath ) { - CompileEnvironment env = new CompileEnvironment(MessageCollector.PLAIN_TEXT_TO_SYSTEM_ERR, CompilerDependencies.compilerDependenciesForProduction(CompilerSpecialMode.REGULAR)); + private CompileEnvironmentConfiguration env( String stdlib, String[] classpath ) { + CompilerDependencies dependencies = CompilerDependencies.compilerDependenciesForProduction(CompilerSpecialMode.REGULAR); + JetCoreEnvironment environment = new JetCoreEnvironment(CompileEnvironmentUtil.createMockDisposable(), dependencies); + CompileEnvironmentConfiguration env = new CompileEnvironmentConfiguration(environment, dependencies, MessageCollector.PLAIN_TEXT_TO_SYSTEM_ERR); if (( stdlib != null ) && ( stdlib.trim().length() > 0 )) { - env.setStdlib( stdlib ); + File file = new File(stdlib); + CompileEnvironmentUtil.addToClasspath(env.getEnvironment(), file); } if (( classpath != null ) && ( classpath.length > 0 )) { - env.addToClasspath( classpath ); + CompileEnvironmentUtil.addToClasspath(env.getEnvironment(), classpath); } // lets register any compiler plugins @@ -92,7 +93,8 @@ public class BytecodeCompiler { */ public void sourcesToDir ( @NotNull String src, @NotNull String output, @Nullable String stdlib, @Nullable String[] classpath ) { try { - boolean success = env( stdlib, classpath ).compileBunchOfSources( src, null, output, true /* Last arg is ignored anyway */ ); + boolean success = KotlinToJVMBytecodeCompiler.compileBunchOfSources(env(stdlib, classpath), src, null, output, true + /* Last arg is ignored anyway */); if ( ! success ) { throw new CompileEnvironmentException( errorMessage( src, false )); } @@ -114,7 +116,7 @@ public class BytecodeCompiler { */ public void sourcesToJar ( @NotNull String src, @NotNull String jar, boolean includeRuntime, @Nullable String stdlib, @Nullable String[] classpath ) { try { - boolean success = env( stdlib, classpath ).compileBunchOfSources( src, jar, null, includeRuntime ); + boolean success = KotlinToJVMBytecodeCompiler.compileBunchOfSources(env(stdlib, classpath), src, jar, null, includeRuntime); if ( ! success ) { throw new CompileEnvironmentException( errorMessage( src, false )); } @@ -136,7 +138,8 @@ public class BytecodeCompiler { */ public void moduleToJar ( @NotNull String module, @NotNull String jar, boolean includeRuntime, @Nullable String stdlib, @Nullable String[] classpath ) { try { - boolean success = env( stdlib, classpath ).compileModuleScript( module, jar, null, includeRuntime); + CompileEnvironmentConfiguration env = env(stdlib, classpath); + boolean success = KotlinToJVMBytecodeCompiler.compileModuleScript(env, module, jar, null, includeRuntime); if ( ! success ) { throw new CompileEnvironmentException( errorMessage( module, false )); } diff --git a/compiler/cli/src/org/jetbrains/jet/cli/KotlinCompiler.java b/compiler/cli/src/org/jetbrains/jet/cli/KotlinCompiler.java index 8be718f846a..1b058ad0151 100644 --- a/compiler/cli/src/org/jetbrains/jet/cli/KotlinCompiler.java +++ b/compiler/cli/src/org/jetbrains/jet/cli/KotlinCompiler.java @@ -20,11 +20,11 @@ import com.google.common.base.Splitter; import com.google.common.collect.Iterables; import com.google.common.collect.LinkedHashMultimap; import com.google.common.collect.Multimap; +import com.intellij.openapi.Disposable; +import com.intellij.openapi.util.Disposer; import com.sampullara.cli.Args; import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.compiler.CompileEnvironment; -import org.jetbrains.jet.compiler.CompileEnvironmentException; -import org.jetbrains.jet.compiler.CompilerPlugin; +import org.jetbrains.jet.compiler.*; import org.jetbrains.jet.compiler.messages.CompilerMessageLocation; import org.jetbrains.jet.compiler.messages.CompilerMessageSeverity; import org.jetbrains.jet.compiler.messages.MessageCollector; @@ -135,23 +135,30 @@ public class KotlinCompiler { runtimeJar = null; } - CompilerDependencies dependencies = new CompilerDependencies(mode, jdkHeadersJar,runtimeJar); + CompilerDependencies dependencies = new CompilerDependencies(mode, jdkHeadersJar, runtimeJar); PrintingMessageCollector messageCollector = new PrintingMessageCollector(errStream, messageRenderer, arguments.verbose); - CompileEnvironment environment = new CompileEnvironment(messageCollector, dependencies); + Disposable rootDisposable = CompileEnvironmentUtil.createMockDisposable(); + + JetCoreEnvironment environment = new JetCoreEnvironment(rootDisposable, dependencies); + CompileEnvironmentConfiguration configuration = new CompileEnvironmentConfiguration(environment, dependencies, messageCollector); try { - configureEnvironment(environment, arguments); + configureEnvironment(configuration, arguments); boolean noErrors; if (arguments.module != null) { - noErrors = environment.compileModuleScript(arguments.module, arguments.jar, arguments.outputDir, arguments.includeRuntime); + noErrors = KotlinToJVMBytecodeCompiler.compileModuleScript(configuration, + arguments.module, arguments.jar, arguments.outputDir, + arguments.includeRuntime); } else { // TODO ideally we'd unify to just having a single field that supports multiple files/dirs if (arguments.getSourceDirs() != null) { - noErrors = environment.compileBunchOfSourceDirectories(arguments.getSourceDirs(), arguments.jar, arguments.outputDir, arguments.includeRuntime); + noErrors = KotlinToJVMBytecodeCompiler.compileBunchOfSourceDirectories(configuration, + arguments.getSourceDirs(), arguments.jar, arguments.outputDir, arguments.includeRuntime); } else { - noErrors = environment.compileBunchOfSources(arguments.src, arguments.jar, arguments.outputDir, arguments.includeRuntime); + noErrors = KotlinToJVMBytecodeCompiler.compileBunchOfSources(configuration, + arguments.src, arguments.jar, arguments.outputDir, arguments.includeRuntime); } } return noErrors ? OK : COMPILATION_ERROR; @@ -161,7 +168,7 @@ public class KotlinCompiler { return INTERNAL_ERROR; } finally { - environment.dispose(); + Disposer.dispose(rootDisposable); messageCollector.printToErrStream(); } } @@ -228,20 +235,20 @@ public class KotlinCompiler { * Strategy method to configure the environment, allowing compiler * based tools to customise their own plugins */ - protected void configureEnvironment(CompileEnvironment environment, CompilerArguments arguments) { + protected void configureEnvironment(CompileEnvironmentConfiguration configuration, CompilerArguments arguments) { // install any compiler plugins List plugins = arguments.getCompilerPlugins(); if (plugins != null) { - environment.getEnvironment().getCompilerPlugins().addAll(plugins); + configuration.getEnvironment().getCompilerPlugins().addAll(plugins); } - if (environment.getCompilerDependencies().getRuntimeJar() != null) { - environment.addToClasspath(environment.getCompilerDependencies().getRuntimeJar()); + if (configuration.getCompilerDependencies().getRuntimeJar() != null) { + CompileEnvironmentUtil.addToClasspath(configuration.getEnvironment(), configuration.getCompilerDependencies().getRuntimeJar()); } if (arguments.classpath != null) { final Iterable classpath = Splitter.on(File.pathSeparatorChar).split(arguments.classpath); - environment.addToClasspath(Iterables.toArray(classpath, String.class)); + CompileEnvironmentUtil.addToClasspath(configuration.getEnvironment(), Iterables.toArray(classpath, String.class)); } } diff --git a/compiler/cli/src/org/jetbrains/jet/compiler/CompileEnvironment.java b/compiler/cli/src/org/jetbrains/jet/compiler/CompileEnvironment.java deleted file mode 100644 index ac22091f949..00000000000 --- a/compiler/cli/src/org/jetbrains/jet/compiler/CompileEnvironment.java +++ /dev/null @@ -1,243 +0,0 @@ -/* - * Copyright 2010-2012 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.jet.compiler; - -import com.intellij.openapi.Disposable; -import com.intellij.openapi.util.Disposer; -import com.intellij.testFramework.LightVirtualFile; -import com.intellij.util.LocalTimeCounter; -import jet.modules.Module; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.codegen.ClassFileFactory; -import org.jetbrains.jet.codegen.GeneratedClassLoader; -import org.jetbrains.jet.codegen.GenerationState; -import org.jetbrains.jet.compiler.messages.MessageCollector; -import org.jetbrains.jet.lang.psi.JetFile; -import org.jetbrains.jet.lang.psi.JetPsiUtil; -import org.jetbrains.jet.lang.resolve.FqName; -import org.jetbrains.jet.lang.resolve.java.CompilerDependencies; -import org.jetbrains.jet.lang.resolve.java.JvmAbi; -import org.jetbrains.jet.plugin.JetLanguage; -import org.jetbrains.jet.plugin.JetMainDetector; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.util.List; - -/** - * The environment for compiling a bunch of source files or - * - * @author yole - */ -public class CompileEnvironment { - private final Disposable rootDisposable; - private JetCoreEnvironment environment; - - private final MessageCollector messageCollector; - - @NotNull - private final CompilerDependencies compilerDependencies; - - /** - * NOTE: It's very important to call dispose for every object of this class or there will be memory leaks. - * @see Disposer - */ - public CompileEnvironment(@NotNull MessageCollector messageCollector, @NotNull CompilerDependencies compilerDependencies) { - this.messageCollector = messageCollector; - this.compilerDependencies = compilerDependencies; - this.rootDisposable = new Disposable() { - @Override - public void dispose() { - } - }; - this.environment = new JetCoreEnvironment(rootDisposable, compilerDependencies); - } - - - public void dispose() { - Disposer.dispose(rootDisposable); - } - - public boolean compileModuleScript(String moduleScriptFile, @Nullable String jarPath, @Nullable String outputDir, boolean jarRuntime) { - List modules = CompileEnvironmentUtil.loadModuleScript(moduleScriptFile, messageCollector); - - if (modules == null) { - throw new CompileEnvironmentException("Module script " + moduleScriptFile + " compilation failed"); - } - - if (modules.isEmpty()) { - throw new CompileEnvironmentException("No modules where defined by " + moduleScriptFile); - } - - final String directory = new File(moduleScriptFile).getParent(); - for (Module moduleBuilder : modules) { - if (compilerDependencies.getRuntimeJar() != null) { - addToClasspath(compilerDependencies.getRuntimeJar()); - } - ClassFileFactory moduleFactory = compileModule(moduleBuilder, directory); - if (moduleFactory == null) { - return false; - } - if (outputDir != null) { - CompileEnvironmentUtil.writeToOutputDirectory(moduleFactory, outputDir); - } - else { - String path = jarPath != null ? jarPath : new File(directory, moduleBuilder.getModuleName() + ".jar").getPath(); - try { - CompileEnvironmentUtil.writeToJar(moduleFactory, new FileOutputStream(path), null, jarRuntime); - } - catch (FileNotFoundException e) { - throw new CompileEnvironmentException("Invalid jar path " + path, e); - } - } - } - return true; - } - - public ClassFileFactory compileModule(Module moduleBuilder, String directory) { - if (moduleBuilder.getSourceFiles().isEmpty()) { - throw new CompileEnvironmentException("No source files where defined"); - } - - for (String sourceFile : moduleBuilder.getSourceFiles()) { - File source = new File(sourceFile); - if (!source.isAbsolute()) { - source = new File(directory, sourceFile); - } - - if (!source.exists()) { - throw new CompileEnvironmentException("'" + source + "' does not exist"); - } - - environment.addSources(source.getPath()); - } - for (String classpathRoot : moduleBuilder.getClasspathRoots()) { - environment.addToClasspath(new File(classpathRoot)); - } - - CompileEnvironmentUtil.ensureRuntime(environment, compilerDependencies); - - return analyze(); - } - - public ClassLoader compileText(String code) { - environment.addSources(new LightVirtualFile("script" + LocalTimeCounter.currentTime() + ".kt", JetLanguage.INSTANCE, code)); - - ClassFileFactory factory = analyze(); - if (factory == null) { - return null; - } - return new GeneratedClassLoader(factory); - } - - public boolean compileBunchOfSources(String sourceFileOrDir, String jar, String outputDir, boolean includeRuntime) { - environment.addSources(sourceFileOrDir); - - return compileBunchOfSources(jar, outputDir, includeRuntime); - } - - public boolean compileBunchOfSourceDirectories(List sources, String jar, String outputDir, boolean includeRuntime) { - for (String source : sources) { - environment.addSources(source); - } - - return compileBunchOfSources(jar, outputDir, includeRuntime); - } - - private boolean compileBunchOfSources(String jar, String outputDir, boolean includeRuntime) { - FqName mainClass = null; - for (JetFile file : environment.getSourceFiles()) { - if (JetMainDetector.hasMain(file.getDeclarations())) { - FqName fqName = JetPsiUtil.getFQName(file); - mainClass = fqName.child(JvmAbi.PACKAGE_CLASS); - break; - } - } - - CompileEnvironmentUtil.ensureRuntime(environment, compilerDependencies); - - ClassFileFactory factory = analyze(); - if (factory == null) { - return false; - } - - if (jar != null) { - try { - CompileEnvironmentUtil.writeToJar(factory, new FileOutputStream(jar), mainClass, includeRuntime); - } catch (FileNotFoundException e) { - throw new CompileEnvironmentException("Invalid jar path " + jar, e); - } - } - else if (outputDir != null) { - CompileEnvironmentUtil.writeToOutputDirectory(factory, outputDir); - } - else { - throw new CompileEnvironmentException("Output directory or jar file is not specified - no files will be saved to the disk"); - } - return true; - } - - private ClassFileFactory analyze() { - boolean stubs = compilerDependencies.getCompilerSpecialMode().isStubs(); - GenerationState generationState = - KotlinToJVMBytecodeCompiler - .analyzeAndGenerate(environment, compilerDependencies, messageCollector, stubs); - if (generationState == null) { - return null; - } - return generationState.getFactory(); - } - - /** - * Add path specified to the compilation environment. - * @param paths paths to add - */ - public void addToClasspath(File ... paths) { - for (File path : paths) { - if (!path.exists()) { - throw new CompileEnvironmentException("'" + path + "' does not exist"); - } - environment.addToClasspath(path); - } - } - - /** - * Add path specified to the compilation environment. - * @param paths paths to add - */ - public void addToClasspath(String ... paths) { - for (String path : paths) { - addToClasspath( new File(path)); - } - } - - public void setStdlib(String stdlib) { - File file = new File(stdlib); - addToClasspath(file); - } - - public JetCoreEnvironment getEnvironment() { - return environment; - } - - @NotNull - public CompilerDependencies getCompilerDependencies() { - return compilerDependencies; - } -} diff --git a/compiler/cli/src/org/jetbrains/jet/compiler/CompileEnvironmentConfiguration.java b/compiler/cli/src/org/jetbrains/jet/compiler/CompileEnvironmentConfiguration.java new file mode 100644 index 00000000000..2b73bd0e964 --- /dev/null +++ b/compiler/cli/src/org/jetbrains/jet/compiler/CompileEnvironmentConfiguration.java @@ -0,0 +1,56 @@ +/* + * Copyright 2010-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.compiler; + +import com.intellij.openapi.util.Disposer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.compiler.messages.MessageCollector; +import org.jetbrains.jet.lang.resolve.java.CompilerDependencies; + +/** + * @author abreslav + */ +public class CompileEnvironmentConfiguration { + private final JetCoreEnvironment environment; + private final CompilerDependencies compilerDependencies; + private final MessageCollector messageCollector; + + /** + * NOTE: It's very important to call dispose for every object of this class or there will be memory leaks. + * @see Disposer + */ + public CompileEnvironmentConfiguration(@NotNull JetCoreEnvironment environment, + @NotNull CompilerDependencies compilerDependencies, @NotNull MessageCollector messageCollector) { + this.messageCollector = messageCollector; + this.compilerDependencies = compilerDependencies; + this.environment = environment; + } + + public JetCoreEnvironment getEnvironment() { + return environment; + } + + @NotNull + public CompilerDependencies getCompilerDependencies() { + return compilerDependencies; + } + + @NotNull + public MessageCollector getMessageCollector() { + return messageCollector; + } +} diff --git a/compiler/cli/src/org/jetbrains/jet/compiler/CompileEnvironmentUtil.java b/compiler/cli/src/org/jetbrains/jet/compiler/CompileEnvironmentUtil.java index eaf0af30966..97f882b486f 100644 --- a/compiler/cli/src/org/jetbrains/jet/compiler/CompileEnvironmentUtil.java +++ b/compiler/cli/src/org/jetbrains/jet/compiler/CompileEnvironmentUtil.java @@ -51,9 +51,17 @@ import java.util.jar.*; * @author abreslav */ public class CompileEnvironmentUtil { + public static Disposable createMockDisposable() { + return new Disposable() { + @Override + public void dispose() { + } + }; + } + @Nullable public static File getUnpackedRuntimePath() { - URL url = CompileEnvironment.class.getClassLoader().getResource("jet/JetObject.class"); + URL url = CompileEnvironmentConfiguration.class.getClassLoader().getResource("jet/JetObject.class"); if (url != null && url.getProtocol().equals("file")) { return new File(url.getPath()).getParentFile().getParentFile(); } @@ -62,7 +70,7 @@ public class CompileEnvironmentUtil { @Nullable public static File getRuntimeJarPath() { - URL url = CompileEnvironment.class.getClassLoader().getResource("jet/JetObject.class"); + URL url = CompileEnvironmentConfiguration.class.getClassLoader().getResource("jet/JetObject.class"); if (url != null && url.getProtocol().equals("jar")) { String path = url.getPath(); return new File(path.substring(path.indexOf(":") + 1, path.indexOf("!/"))); @@ -187,7 +195,7 @@ public class CompileEnvironmentUtil { } } else { - loader = new GeneratedClassLoader(factory, CompileEnvironment.class.getClassLoader()); + loader = new GeneratedClassLoader(factory, CompileEnvironmentConfiguration.class.getClassLoader()); } try { Class namespaceClass = loader.loadClass(JvmAbi.PACKAGE_CLASS); @@ -301,4 +309,29 @@ public class CompileEnvironmentUtil { } } } + + /** + * Add path specified to the compilation environment. + * @param environment compilation environment to add to + * @param paths paths to add + */ + public static void addToClasspath(JetCoreEnvironment environment, File ... paths) { + for (File path : paths) { + if (!path.exists()) { + throw new CompileEnvironmentException("'" + path + "' does not exist"); + } + environment.addToClasspath(path); + } + } + + /** + * Add path specified to the compilation environment. + * @param environment compilation environment to add to + * @param paths paths to add + */ + public static void addToClasspath(JetCoreEnvironment environment, String ... paths) { + for (String path : paths) { + addToClasspath(environment, new File(path)); + } + } } diff --git a/compiler/cli/src/org/jetbrains/jet/compiler/KotlinToJVMBytecodeCompiler.java b/compiler/cli/src/org/jetbrains/jet/compiler/KotlinToJVMBytecodeCompiler.java index ecc239820ad..a6055710614 100644 --- a/compiler/cli/src/org/jetbrains/jet/compiler/KotlinToJVMBytecodeCompiler.java +++ b/compiler/cli/src/org/jetbrains/jet/compiler/KotlinToJVMBytecodeCompiler.java @@ -25,12 +25,13 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiErrorElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiRecursiveElementWalkingVisitor; +import com.intellij.testFramework.LightVirtualFile; +import com.intellij.util.LocalTimeCounter; +import jet.modules.Module; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.analyzer.AnalyzeExhaust; -import org.jetbrains.jet.codegen.ClassBuilderFactories; -import org.jetbrains.jet.codegen.CompilationErrorHandler; -import org.jetbrains.jet.codegen.GenerationState; +import org.jetbrains.jet.codegen.*; import org.jetbrains.jet.compiler.messages.CompilerMessageLocation; import org.jetbrains.jet.compiler.messages.CompilerMessageSeverity; import org.jetbrains.jet.compiler.messages.MessageCollector; @@ -41,12 +42,20 @@ import org.jetbrains.jet.lang.diagnostics.DiagnosticFactory; import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils; import org.jetbrains.jet.lang.diagnostics.Severity; import org.jetbrains.jet.lang.psi.JetFile; +import org.jetbrains.jet.lang.psi.JetPsiUtil; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.DescriptorUtils; +import org.jetbrains.jet.lang.resolve.FqName; import org.jetbrains.jet.lang.resolve.java.AnalyzerFacadeForJVM; import org.jetbrains.jet.lang.resolve.java.CompilerDependencies; +import org.jetbrains.jet.lang.resolve.java.JvmAbi; +import org.jetbrains.jet.plugin.JetLanguage; +import org.jetbrains.jet.plugin.JetMainDetector; import org.jetbrains.jet.utils.Progress; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.util.Collection; import java.util.List; @@ -56,6 +65,163 @@ import java.util.List; */ public class KotlinToJVMBytecodeCompiler { + @Nullable + public static ClassFileFactory compileModule( + CompileEnvironmentConfiguration configuration, + Module moduleBuilder, + String directory + ) { + if (moduleBuilder.getSourceFiles().isEmpty()) { + throw new CompileEnvironmentException("No source files where defined"); + } + + for (String sourceFile : moduleBuilder.getSourceFiles()) { + File source = new File(sourceFile); + if (!source.isAbsolute()) { + source = new File(directory, sourceFile); + } + + if (!source.exists()) { + throw new CompileEnvironmentException("'" + source + "' does not exist"); + } + + configuration.getEnvironment().addSources(source.getPath()); + } + for (String classpathRoot : moduleBuilder.getClasspathRoots()) { + configuration.getEnvironment().addToClasspath(new File(classpathRoot)); + } + + CompileEnvironmentUtil.ensureRuntime(configuration.getEnvironment(), configuration.getCompilerDependencies()); + + GenerationState generationState = analyzeAndGenerate(configuration); + if (generationState == null) { + return null; + } + return generationState.getFactory(); + } + + public static boolean compileModuleScript( + CompileEnvironmentConfiguration configuration, + + @NotNull String moduleScriptFile, + @Nullable String jarPath, + @Nullable String outputDir, + boolean jarRuntime) { + List modules = CompileEnvironmentUtil.loadModuleScript(moduleScriptFile, configuration.getMessageCollector()); + + if (modules == null) { + throw new CompileEnvironmentException("Module script " + moduleScriptFile + " compilation failed"); + } + + if (modules.isEmpty()) { + throw new CompileEnvironmentException("No modules where defined by " + moduleScriptFile); + } + + final String directory = new File(moduleScriptFile).getParent(); + for (Module moduleBuilder : modules) { + // TODO: this should be done only once for the environment + if (configuration.getCompilerDependencies().getRuntimeJar() != null) { + CompileEnvironmentUtil.addToClasspath(configuration.getEnvironment(), configuration.getCompilerDependencies().getRuntimeJar()); + } + ClassFileFactory moduleFactory = KotlinToJVMBytecodeCompiler.compileModule(configuration, moduleBuilder, directory); + if (moduleFactory == null) { + return false; + } + if (outputDir != null) { + CompileEnvironmentUtil.writeToOutputDirectory(moduleFactory, outputDir); + } + else { + String path = jarPath != null ? jarPath : new File(directory, moduleBuilder.getModuleName() + ".jar").getPath(); + try { + CompileEnvironmentUtil.writeToJar(moduleFactory, new FileOutputStream(path), null, jarRuntime); + } + catch (FileNotFoundException e) { + throw new CompileEnvironmentException("Invalid jar path " + path, e); + } + } + } + return true; + } + + private static boolean compileBunchOfSources( + CompileEnvironmentConfiguration configuration, + + String jar, + String outputDir, + boolean includeRuntime + ) { + FqName mainClass = null; + for (JetFile file : configuration.getEnvironment().getSourceFiles()) { + if (JetMainDetector.hasMain(file.getDeclarations())) { + FqName fqName = JetPsiUtil.getFQName(file); + mainClass = fqName.child(JvmAbi.PACKAGE_CLASS); + break; + } + } + + CompileEnvironmentUtil.ensureRuntime(configuration.getEnvironment(), configuration.getCompilerDependencies()); + + GenerationState generationState = analyzeAndGenerate(configuration); + if (generationState == null) { + return false; + } + + ClassFileFactory factory = generationState.getFactory(); + if (jar != null) { + try { + CompileEnvironmentUtil.writeToJar(factory, new FileOutputStream(jar), mainClass, includeRuntime); + } catch (FileNotFoundException e) { + throw new CompileEnvironmentException("Invalid jar path " + jar, e); + } + } + else if (outputDir != null) { + CompileEnvironmentUtil.writeToOutputDirectory(factory, outputDir); + } + else { + throw new CompileEnvironmentException("Output directory or jar file is not specified - no files will be saved to the disk"); + } + return true; + } + + public static boolean compileBunchOfSources( + CompileEnvironmentConfiguration configuration, + + String sourceFileOrDir, String jar, String outputDir, boolean includeRuntime) { + configuration.getEnvironment().addSources(sourceFileOrDir); + + return compileBunchOfSources(configuration, jar, outputDir, includeRuntime); + } + + public static boolean compileBunchOfSourceDirectories( + CompileEnvironmentConfiguration configuration, + + List sources, String jar, String outputDir, boolean includeRuntime) { + for (String source : sources) { + configuration.getEnvironment().addSources(source); + } + + return compileBunchOfSources(configuration, jar, outputDir, includeRuntime); + } + + @Nullable + public static ClassLoader compileText( + CompileEnvironmentConfiguration configuration, + + String code) { + configuration.getEnvironment().addSources(new LightVirtualFile("script" + LocalTimeCounter.currentTime() + ".kt", JetLanguage.INSTANCE, code)); + + GenerationState generationState = analyzeAndGenerate(configuration); + if (generationState == null) { + return null; + } + return new GeneratedClassLoader(generationState.getFactory()); + } + + @Nullable + public static GenerationState analyzeAndGenerate(CompileEnvironmentConfiguration configuration) { + return analyzeAndGenerate(configuration.getEnvironment(), configuration.getCompilerDependencies(), configuration.getMessageCollector(), configuration.getCompilerDependencies().getCompilerSpecialMode().isStubs()); + } + @Nullable public static GenerationState analyzeAndGenerate( JetCoreEnvironment environment, diff --git a/compiler/tests/org/jetbrains/jet/codegen/CompileTextTest.java b/compiler/tests/org/jetbrains/jet/codegen/CompileTextTest.java index 84d8b82c38c..aacc2ca0d65 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/CompileTextTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/CompileTextTest.java @@ -17,8 +17,12 @@ package org.jetbrains.jet.codegen; import org.jetbrains.jet.CompileCompilerDependenciesTest; -import org.jetbrains.jet.compiler.CompileEnvironment; +import org.jetbrains.jet.compiler.CompileEnvironmentConfiguration; +import org.jetbrains.jet.compiler.CompileEnvironmentUtil; +import org.jetbrains.jet.compiler.JetCoreEnvironment; +import org.jetbrains.jet.compiler.KotlinToJVMBytecodeCompiler; import org.jetbrains.jet.compiler.messages.MessageCollector; +import org.jetbrains.jet.lang.resolve.java.CompilerDependencies; import org.jetbrains.jet.lang.resolve.java.CompilerSpecialMode; import java.lang.reflect.InvocationTargetException; @@ -27,9 +31,11 @@ import java.lang.reflect.Method; public class CompileTextTest extends CodegenTestCase { public void testMe() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { String text = "import org.jetbrains.jet.codegen.CompileTextTest; fun x() = CompileTextTest()"; - CompileEnvironment compileEnvironment = new CompileEnvironment(MessageCollector.PLAIN_TEXT_TO_SYSTEM_ERR, CompileCompilerDependenciesTest.compilerDependenciesForTests(CompilerSpecialMode.REGULAR)); - compileEnvironment.getEnvironment().addToClasspathFromClassLoader(getClass().getClassLoader()); - ClassLoader classLoader = compileEnvironment.compileText(text); + CompilerDependencies dependencies = CompileCompilerDependenciesTest.compilerDependenciesForTests(CompilerSpecialMode.REGULAR); + JetCoreEnvironment environment = new JetCoreEnvironment(CompileEnvironmentUtil.createMockDisposable(), dependencies); + CompileEnvironmentConfiguration configuration = new CompileEnvironmentConfiguration(environment, dependencies, MessageCollector.PLAIN_TEXT_TO_SYSTEM_ERR); + configuration.getEnvironment().addToClasspathFromClassLoader(getClass().getClassLoader()); + ClassLoader classLoader = KotlinToJVMBytecodeCompiler.compileText(configuration, text); Class namespace = classLoader.loadClass("namespace"); Method x = namespace.getDeclaredMethod("x"); Object invoke = x.invoke(null); diff --git a/compiler/tests/org/jetbrains/jet/codegen/StdlibTest.java b/compiler/tests/org/jetbrains/jet/codegen/StdlibTest.java index 20f6a1892d4..6e18a9aa08c 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/StdlibTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/StdlibTest.java @@ -17,8 +17,8 @@ package org.jetbrains.jet.codegen; import org.jetbrains.jet.codegen.forTestCompile.ForTestCompileRuntime; -import org.jetbrains.jet.compiler.CompileEnvironment; import org.jetbrains.jet.lang.psi.JetPsiUtil; +import org.junit.Test; import java.io.File; import java.lang.annotation.*; @@ -28,8 +28,6 @@ import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; -import org.junit.Test; - /** * @author alex.tkachman */