diff --git a/compiler/cli/src/org/jetbrains/jet/compiler/CompileEnvironment.java b/compiler/cli/src/org/jetbrains/jet/compiler/CompileEnvironment.java index 5520ca89347..de387514549 100644 --- a/compiler/cli/src/org/jetbrains/jet/compiler/CompileEnvironment.java +++ b/compiler/cli/src/org/jetbrains/jet/compiler/CompileEnvironment.java @@ -25,6 +25,7 @@ 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.lang.psi.JetFile; import org.jetbrains.jet.lang.psi.JetPsiUtil; import org.jetbrains.jet.lang.resolve.FqName; @@ -125,9 +126,6 @@ public class CompileEnvironment { } public ClassFileFactory compileModule(Module moduleBuilder, String directory) { - CompileSession moduleCompileSession = newCompileSession(); - moduleCompileSession.setStubs(compilerDependencies.getCompilerSpecialMode().isStubs()); - if (moduleBuilder.getSourceFiles().isEmpty()) { throw new CompileEnvironmentException("No source files where defined"); } @@ -150,45 +148,34 @@ public class CompileEnvironment { CompileEnvironmentUtil.ensureRuntime(environment, compilerDependencies); - if (!moduleCompileSession.analyze() && !ignoreErrors) { - return null; - } - return moduleCompileSession.generate(false).getFactory(); + return analyze(); } public ClassLoader compileText(String code) { - CompileSession session = newCompileSession(); environment.addSources(new LightVirtualFile("script" + LocalTimeCounter.currentTime() + ".kt", JetLanguage.INSTANCE, code)); - if (!session.analyze() && !ignoreErrors) { + ClassFileFactory factory = analyze(); + if (factory == null) { return null; } - - ClassFileFactory factory = session.generate(false).getFactory(); return new GeneratedClassLoader(factory); } public boolean compileBunchOfSources(String sourceFileOrDir, String jar, String outputDir, boolean includeRuntime) { - CompileSession session = newCompileSession(); - session.setStubs(compilerDependencies.getCompilerSpecialMode().isStubs()); - environment.addSources(sourceFileOrDir); - return compileBunchOfSources(jar, outputDir, includeRuntime, session); + return compileBunchOfSources(jar, outputDir, includeRuntime); } public boolean compileBunchOfSourceDirectories(List sources, String jar, String outputDir, boolean includeRuntime) { - CompileSession session = newCompileSession(); - session.setStubs(compilerDependencies.getCompilerSpecialMode().isStubs()); - for (String source : sources) { environment.addSources(source); } - return compileBunchOfSources(jar, outputDir, includeRuntime, session); + return compileBunchOfSources(jar, outputDir, includeRuntime); } - private boolean compileBunchOfSources(String jar, String outputDir, boolean includeRuntime, CompileSession session) { + private boolean compileBunchOfSources(String jar, String outputDir, boolean includeRuntime) { FqName mainClass = null; for (JetFile file : environment.getSourceFiles()) { if (JetMainDetector.hasMain(file.getDeclarations())) { @@ -200,11 +187,11 @@ public class CompileEnvironment { CompileEnvironmentUtil.ensureRuntime(environment, compilerDependencies); - if (!session.analyze() && !ignoreErrors) { + ClassFileFactory factory = analyze(); + if (factory == null) { return false; } - ClassFileFactory factory = session.generate(false).getFactory(); if (jar != null) { try { CompileEnvironmentUtil.writeToJar(factory, new FileOutputStream(jar), mainClass, includeRuntime); @@ -221,8 +208,15 @@ public class CompileEnvironment { return true; } - private CompileSession newCompileSession() { - return new CompileSession(environment, messageRenderer, errorStream, verbose, compilerDependencies); + private ClassFileFactory analyze() { + boolean stubs = compilerDependencies.getCompilerSpecialMode().isStubs(); + GenerationState generationState = + KotlinToJVMBytecodeCompiler + .analyzeAndGenerate(environment, compilerDependencies, messageRenderer, errorStream, verbose, stubs); + if (generationState == null) { + return null; + } + return generationState.getFactory(); } /** diff --git a/compiler/cli/src/org/jetbrains/jet/compiler/CompileEnvironmentUtil.java b/compiler/cli/src/org/jetbrains/jet/compiler/CompileEnvironmentUtil.java index 213a94a3c54..8c863e71356 100644 --- a/compiler/cli/src/org/jetbrains/jet/compiler/CompileEnvironmentUtil.java +++ b/compiler/cli/src/org/jetbrains/jet/compiler/CompileEnvironmentUtil.java @@ -27,6 +27,7 @@ import jet.modules.Module; 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.lang.resolve.FqName; import org.jetbrains.jet.lang.resolve.java.CompilerDependencies; import org.jetbrains.jet.lang.resolve.java.CompilerSpecialMode; @@ -159,14 +160,13 @@ public class CompileEnvironmentUtil { ensureRuntime(scriptEnvironment, dependencies); scriptEnvironment.addSources(moduleFile); - CompileSession scriptCompileSession = new CompileSession(scriptEnvironment, messageRenderer, errorStream, verbose, dependencies); - - if (!scriptCompileSession.analyze()) { + GenerationState generationState = KotlinToJVMBytecodeCompiler + .analyzeAndGenerate(scriptEnvironment, dependencies, messageRenderer, errorStream, verbose, false); + if (generationState == null) { return null; } - ClassFileFactory factory = scriptCompileSession.generate(true).getFactory(); - List modules = runDefineModules(dependencies, moduleFile, factory); + List modules = runDefineModules(dependencies, moduleFile, generationState.getFactory()); Disposer.dispose(disposable); return modules; diff --git a/compiler/cli/src/org/jetbrains/jet/compiler/CompileSession.java b/compiler/cli/src/org/jetbrains/jet/compiler/KotlinToJVMBytecodeCompiler.java similarity index 66% rename from compiler/cli/src/org/jetbrains/jet/compiler/CompileSession.java rename to compiler/cli/src/org/jetbrains/jet/compiler/KotlinToJVMBytecodeCompiler.java index 8b6c4a8d1f9..881012194a0 100644 --- a/compiler/cli/src/org/jetbrains/jet/compiler/CompileSession.java +++ b/compiler/cli/src/org/jetbrains/jet/compiler/KotlinToJVMBytecodeCompiler.java @@ -25,6 +25,7 @@ import com.intellij.psi.PsiErrorElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiRecursiveElementWalkingVisitor; 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; @@ -51,46 +52,122 @@ import java.util.Collection; import java.util.List; /** - * The session which handles analyzing and compiling a single module. - * * @author yole + * @author abreslav */ -public class CompileSession { - private final JetCoreEnvironment environment; - private final MessageCollector messageCollector; - private boolean stubs = false; - private final MessageRenderer messageRenderer; - private final PrintStream errorStream; - private final boolean verbose; - private final CompilerDependencies compilerDependencies; - private AnalyzeExhaust bindingContext; +public class KotlinToJVMBytecodeCompiler { - public CompileSession(JetCoreEnvironment environment, MessageRenderer messageRenderer, PrintStream errorStream, boolean verbose, - @NotNull CompilerDependencies compilerDependencies) { - this.environment = environment; - this.messageRenderer = messageRenderer; - this.errorStream = errorStream; - this.verbose = verbose; - this.compilerDependencies = compilerDependencies; - this.messageCollector = new MessageCollector(this.messageRenderer); + @Nullable + public static GenerationState analyzeAndGenerate( + JetCoreEnvironment environment, + CompilerDependencies dependencies, + + MessageRenderer messageRenderer, + PrintStream errorStream, + boolean verbose, + + boolean stubs + ) { + AnalyzeExhaust exhaust = analyze(environment, dependencies, messageRenderer, errorStream, stubs); + + if (exhaust == null) { + return null; + } + + return generate(environment, dependencies, messageRenderer, errorStream, verbose, exhaust, stubs); } - @NotNull - public AnalyzeExhaust getBindingContext() { - return bindingContext; - } + @Nullable + private static AnalyzeExhaust analyze( + JetCoreEnvironment environment, + CompilerDependencies dependencies, - public void setStubs(boolean stubs) { - this.stubs = stubs; - } + MessageRenderer messageRenderer, + PrintStream errorStream, - public boolean analyze() { - reportSyntaxErrors(); - analyzeAndReportSemanticErrors(); + boolean stubs) { + final MessageCollector messageCollector = new MessageCollector(messageRenderer); + + //reportSyntaxErrors(); + for (JetFile file : environment.getSourceFiles()) { + file.accept(new PsiRecursiveElementWalkingVisitor() { + @Override + public void visitErrorElement(PsiErrorElement element) { + String description = element.getErrorDescription(); + String message = StringUtil.isEmpty(description) ? "Syntax error" : description; + Diagnostic diagnostic = DiagnosticFactory.create(Severity.ERROR, message).on(element); + reportDiagnostic(messageCollector, diagnostic); + } + }); + } + + //analyzeAndReportSemanticErrors(); + Predicate filesToAnalyzeCompletely = + stubs ? Predicates.alwaysFalse() : Predicates.alwaysTrue(); + AnalyzeExhaust exhaust = AnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration( + environment.getProject(), environment.getSourceFiles(), filesToAnalyzeCompletely, JetControlFlowDataTraceFactory.EMPTY, + dependencies); + + for (Diagnostic diagnostic : exhaust.getBindingContext().getDiagnostics()) { + reportDiagnostic(messageCollector, diagnostic); + } + + reportIncompleteHierarchies(messageCollector, exhaust); messageCollector.printTo(errorStream); - return !messageCollector.hasErrors(); + return messageCollector.hasErrors() ? null : exhaust; + } + + @NotNull + private static GenerationState generate( + JetCoreEnvironment environment, + CompilerDependencies dependencies, + + final MessageRenderer messageRenderer, + final PrintStream errorStream, + boolean verbose, + + AnalyzeExhaust exhaust, + + boolean stubs) { + Project project = environment.getProject(); + class BackendProgress implements Progress { + @Override + public void log(String message) { + errorStream.println(messageRenderer.render(Severity.LOGGING, message, null, -1, -1)); + } + } + GenerationState generationState = new GenerationState(project, ClassBuilderFactories.binaries(stubs), + verbose ? new BackendProgress() : Progress.DEAF, exhaust, environment.getSourceFiles(), dependencies.getCompilerSpecialMode()); + generationState.compileCorrectFiles(CompilationErrorHandler.THROW_EXCEPTION); + + List plugins = environment.getCompilerPlugins(); + if (plugins != null) { + CompilerPluginContext context = new CompilerPluginContext(project, exhaust.getBindingContext(), environment.getSourceFiles()); + for (CompilerPlugin plugin : plugins) { + plugin.processFiles(context); + } + } + return generationState; + } + + private static void reportDiagnostic(MessageCollector collector, Diagnostic diagnostic) { + DiagnosticUtils.LineAndColumn lineAndColumn = DiagnosticUtils.getLineAndColumn(diagnostic); + VirtualFile virtualFile = diagnostic.getPsiFile().getVirtualFile(); + String path = virtualFile == null ? null : virtualFile.getPath(); + collector.report(diagnostic.getSeverity(), diagnostic.getMessage(), path, lineAndColumn.getLine(), lineAndColumn.getColumn()); + } + + private static void reportIncompleteHierarchies(MessageCollector collector, AnalyzeExhaust exhaust) { + Collection incompletes = exhaust.getBindingContext().getKeys(BindingContext.INCOMPLETE_HIERARCHY); + if (!incompletes.isEmpty()) { + StringBuilder message = new StringBuilder("The following classes have incomplete hierarchies:\n"); + for (ClassDescriptor incomplete : incompletes) { + message.append(" ").append(fqName(incomplete)).append("\n"); + } + collector.report(Severity.ERROR, message.toString(), null, -1, -1); + } } /** @@ -106,76 +183,4 @@ public class CompileSession { return fqName((ClassOrNamespaceDescriptor) containingDeclaration) + "." + descriptor.getName(); } } - - private void analyzeAndReportSemanticErrors() { - Predicate filesToAnalyzeCompletely = - stubs ? Predicates.alwaysFalse() : Predicates.alwaysTrue(); - bindingContext = AnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration( - environment.getProject(), environment.getSourceFiles(), filesToAnalyzeCompletely, JetControlFlowDataTraceFactory.EMPTY, - compilerDependencies); - - for (Diagnostic diagnostic : bindingContext.getBindingContext().getDiagnostics()) { - reportDiagnostic(messageCollector, diagnostic); - } - - reportIncompleteHierarchies(messageCollector); - } - - private void reportIncompleteHierarchies(MessageCollector collector) { - Collection incompletes = bindingContext.getBindingContext().getKeys(BindingContext.INCOMPLETE_HIERARCHY); - if (!incompletes.isEmpty()) { - StringBuilder message = new StringBuilder("The following classes have incomplete hierarchies:\n"); - for (ClassDescriptor incomplete : incompletes) { - message.append(" ").append(fqName(incomplete)).append("\n"); - } - collector.report(Severity.ERROR, message.toString(), null, -1, -1); - } - } - - private void reportSyntaxErrors() { - for (JetFile file : environment.getSourceFiles()) { - file.accept(new PsiRecursiveElementWalkingVisitor() { - @Override - public void visitErrorElement(PsiErrorElement element) { - String description = element.getErrorDescription(); - String message = StringUtil.isEmpty(description) ? "Syntax error" : description; - Diagnostic diagnostic = DiagnosticFactory.create(Severity.ERROR, message).on(element); - reportDiagnostic(messageCollector, diagnostic); - } - }); - } - } - - private static void reportDiagnostic(MessageCollector collector, Diagnostic diagnostic) { - DiagnosticUtils.LineAndColumn lineAndColumn = DiagnosticUtils.getLineAndColumn(diagnostic); - VirtualFile virtualFile = diagnostic.getPsiFile().getVirtualFile(); - String path = virtualFile == null ? null : virtualFile.getPath(); - collector.report(diagnostic.getSeverity(), diagnostic.getMessage(), path, lineAndColumn.getLine(), lineAndColumn.getColumn()); - } - - @NotNull - public GenerationState generate(boolean module) { - Project project = environment.getProject(); - GenerationState generationState = new GenerationState(project, ClassBuilderFactories.binaries(stubs), - verbose ? new BackendProgress() : Progress.DEAF, bindingContext, environment.getSourceFiles(), compilerDependencies.getCompilerSpecialMode()); - generationState.compileCorrectFiles(CompilationErrorHandler.THROW_EXCEPTION); - - List plugins = environment.getCompilerPlugins(); - if (!module) { - if (plugins != null) { - CompilerPluginContext context = new CompilerPluginContext(project, bindingContext.getBindingContext(), environment.getSourceFiles()); - for (CompilerPlugin plugin : plugins) { - plugin.processFiles(context); - } - } - } - return generationState; - } - - private class BackendProgress implements Progress { - @Override - public void log(String message) { - errorStream.println(messageRenderer.render(Severity.LOGGING, message, null, -1, -1)); - } - } } diff --git a/compiler/tests/org/jetbrains/jet/codegen/TestlibTest.java b/compiler/tests/org/jetbrains/jet/codegen/TestlibTest.java index 0196ee196af..6c88fd99ce4 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/TestlibTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/TestlibTest.java @@ -23,7 +23,7 @@ import junit.framework.TestCase; import junit.framework.TestSuite; import org.jetbrains.jet.CompileCompilerDependenciesTest; import org.jetbrains.jet.codegen.forTestCompile.ForTestCompileRuntime; -import org.jetbrains.jet.compiler.CompileSession; +import org.jetbrains.jet.compiler.KotlinToJVMBytecodeCompiler; import org.jetbrains.jet.compiler.MessageRenderer; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.psi.JetClass; @@ -37,6 +37,7 @@ import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.parsing.JetParsingTest; import java.io.File; +import java.io.PrintStream; import java.lang.reflect.Constructor; import java.lang.reflect.Modifier; import java.net.URL; @@ -74,10 +75,8 @@ public class TestlibTest extends CodegenTestCase { private TestSuite doBuildSuite() { try { + PrintStream err = System.err; CompilerDependencies compilerDependencies = CompileCompilerDependenciesTest.compilerDependenciesForTests(CompilerSpecialMode.REGULAR); - CompileSession session = new CompileSession(myEnvironment, MessageRenderer.PLAIN, System.err, false, - compilerDependencies); - File junitJar = new File("libraries/lib/junit-4.9.jar"); if (!junitJar.exists()) { @@ -92,19 +91,21 @@ public class TestlibTest extends CodegenTestCase { myEnvironment.addSources(localFileSystem.findFileByPath(JetParsingTest.getTestDataDir() + "/../../libraries/stdlib/test")); myEnvironment.addSources(localFileSystem.findFileByPath(JetParsingTest.getTestDataDir() + "/../../libraries/kunit/src")); - if (!session.analyze()) { + GenerationState generationState = KotlinToJVMBytecodeCompiler + .analyzeAndGenerate(myEnvironment, compilerDependencies, MessageRenderer.PLAIN, err, false, false); + + if (generationState == null) { throw new RuntimeException("There were compilation errors"); } - GenerationState state = session.generate(false); - ClassFileFactory classFileFactory = state.getFactory(); + ClassFileFactory classFileFactory = generationState.getFactory(); final GeneratedClassLoader loader = new GeneratedClassLoader( classFileFactory, new URLClassLoader(new URL[]{ForTestCompileRuntime.runtimeJarForTests().toURI().toURL(), junitJar.toURI().toURL()}, TestCase.class.getClassLoader())); - JetTypeMapper typeMapper = state.getInjector().getJetTypeMapper(); + JetTypeMapper typeMapper = generationState.getInjector().getJetTypeMapper(); TestSuite suite = new TestSuite("stdlib_test"); try { for(JetFile jetFile : myEnvironment.getSourceFiles()) { @@ -112,7 +113,7 @@ public class TestlibTest extends CodegenTestCase { if(decl instanceof JetClass) { JetClass jetClass = (JetClass) decl; - ClassDescriptor descriptor = (ClassDescriptor) session.getBindingContext().getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, jetClass); + ClassDescriptor descriptor = (ClassDescriptor) generationState.getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, jetClass); Set allSuperTypes = new THashSet(); DescriptorUtils.addSuperTypes(descriptor.getDefaultType(), allSuperTypes);