work in progress on compiler unification between cli and plugin

This commit is contained in:
Alex Tkachman
2011-12-27 17:36:37 +02:00
parent 4272dafc36
commit 725bebc23f
43 changed files with 469 additions and 202 deletions
@@ -1,19 +1,16 @@
package org.jetbrains.jet.compiler;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFileSystem;
import com.intellij.util.Function;
import com.intellij.util.Processor;
import jet.ExtensionFunction0;
import jet.ExtensionFunction10;
import jet.Function1;
import jet.modules.IModuleBuilder;
import jet.modules.IModuleSetBuilder;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.JetCoreEnvironment;
import org.jetbrains.jet.codegen.ClassFileFactory;
import org.jetbrains.jet.codegen.GeneratedClassLoader;
import org.jetbrains.jet.lang.psi.JetNamespace;
@@ -22,7 +19,6 @@ import org.jetbrains.jet.plugin.JetMainDetector;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
@@ -30,74 +26,13 @@ import java.util.List;
import java.util.jar.*;
/**
* The environment for compiling a bunch of source files or
*
* @author yole
* @author alex.tkachman
*/
public class CompileEnvironment {
private JetCoreEnvironment myEnvironment;
private final Disposable myRootDisposable;
private PrintStream myErrorStream = System.out;
public abstract class AbstractCompileEnvironment {
protected Project project;
public CompileEnvironment() {
myRootDisposable = new Disposable() {
@Override
public void dispose() {
}
};
myEnvironment = new JetCoreEnvironment(myRootDisposable);
}
protected abstract void addToClasspath(File file);
public void setErrorStream(PrintStream errorStream) {
myErrorStream = errorStream;
}
public void dispose() {
Disposer.dispose(myRootDisposable);
}
public boolean initializeKotlinRuntime() {
return initializeKotlinRuntime(myEnvironment);
}
public static boolean initializeKotlinRuntime(JetCoreEnvironment environment) {
final File unpackedRuntimePath = getUnpackedRuntimePath();
if (unpackedRuntimePath != null) {
environment.addToClasspath(unpackedRuntimePath);
}
else {
final File runtimeJarPath = getRuntimeJarPath();
if (runtimeJarPath != null && runtimeJarPath.exists()) {
environment.addToClasspath(runtimeJarPath);
}
else {
return false;
}
}
return true;
}
public static File getUnpackedRuntimePath() {
URL url = CompileEnvironment.class.getClassLoader().getResource("jet/JetObject.class");
if (url != null && url.getProtocol().equals("file")) {
return new File(url.getPath()).getParentFile().getParentFile();
}
return null;
}
public static File getRuntimeJarPath() {
URL url = CompileEnvironment.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("!/")));
}
return null;
}
public void setJavaRuntime(File rtJarPath) {
myEnvironment.addToClasspath(rtJarPath);
}
public static File findRtJar(boolean failOnError) {
String javaHome = System.getenv("JAVA_HOME");
File rtJar;
@@ -164,6 +99,52 @@ public class CompileEnvironment {
return null;
}
public abstract VirtualFileSystem getLocalFileSystem();
public abstract VirtualFileSystem getJarFileSystem();
public Project getProject() {
return project;
}
public static File getUnpackedRuntimePath() {
URL url = CoreCompileEnvironment.class.getClassLoader().getResource("jet/JetObject.class");
if (url != null && url.getProtocol().equals("file")) {
return new File(url.getPath()).getParentFile().getParentFile();
}
return null;
}
public static File getRuntimeJarPath() {
URL url = CoreCompileEnvironment.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("!/")));
}
return null;
}
public static boolean initializeKotlinRuntime(AbstractCompileEnvironment environment) {
final File unpackedRuntimePath = getUnpackedRuntimePath();
if (unpackedRuntimePath != null) {
environment.addToClasspath(unpackedRuntimePath);
}
else {
final File runtimeJarPath = getRuntimeJarPath();
if (runtimeJarPath != null && runtimeJarPath.exists()) {
environment.addToClasspath(runtimeJarPath);
}
else {
return false;
}
}
return true;
}
public void setJavaRuntime(File rtJarPath) {
addToClasspath(rtJarPath);
}
public void compileModuleScript(String moduleFile, String jarPath, boolean jarRuntime) {
final IModuleSetBuilder moduleSetBuilder = loadModuleScript(moduleFile);
if (moduleSetBuilder == null) {
@@ -183,11 +164,11 @@ public class CompileEnvironment {
}
public IModuleSetBuilder loadModuleScript(String moduleFile) {
CompileSession scriptCompileSession = new CompileSession(myEnvironment);
CompileSession scriptCompileSession = new CompileSession(this);
scriptCompileSession.addSources(moduleFile);
scriptCompileSession.addStdLibSources();
if (!scriptCompileSession.analyze(myErrorStream)) {
if (!scriptCompileSession.analyze(System.out)) {
return null;
}
final ClassFileFactory factory = scriptCompileSession.generate();
@@ -223,22 +204,22 @@ public class CompileEnvironment {
}
public ClassFileFactory compileModule(IModuleBuilder moduleBuilder, String directory) {
CompileSession moduleCompileSession = new CompileSession(myEnvironment);
CompileSession moduleCompileSession = new CompileSession(this);
moduleCompileSession.addStdLibSources();
for (String sourceFile : moduleBuilder.getSourceFiles()) {
moduleCompileSession.addSources(new File(directory, sourceFile).getPath());
}
for (String classpathRoot : moduleBuilder.getClasspathRoots()) {
myEnvironment.addToClasspath(new File(classpathRoot));
addToClasspath(new File(classpathRoot));
}
if (!moduleCompileSession.analyze(myErrorStream)) {
if (!moduleCompileSession.analyze(System.out)) {
return null;
}
return moduleCompileSession.generate();
}
private static String getHomeDirectory() {
return new File(PathManager.getResourceRoot(CompileEnvironment.class, "/org/jetbrains/jet/compiler/CompileEnvironment.class")).getParentFile().getParentFile().getParent();
return new File(PathManager.getResourceRoot(CoreCompileEnvironment.class, "/org/jetbrains/jet/compiler/CoreCompileEnvironment.class")).getParentFile().getParentFile().getParent();
}
private static final List<String> sanitized = Arrays.asList("kotlin/", "std/");
@@ -331,10 +312,11 @@ public class CompileEnvironment {
}
}
public void compileBunchOfSources(String sourceFileOrDir, String jar, String outputDir, boolean includeRuntime) {
CompileSession session = new CompileSession(myEnvironment);
public void compileBunchOfSources(String sourceFileOrDir, String jar, String outputDir, boolean includeRuntime, boolean stdlib) {
CompileSession session = new CompileSession(this);
session.addSources(sourceFileOrDir);
session.addStdLibSources();
if(!stdlib)
session.addStdLibSources();
String mainClass = null;
for (JetNamespace namespace : session.getSourceFileNamespaces()) {
@@ -343,7 +325,7 @@ public class CompileEnvironment {
break;
}
}
if (!session.analyze(myErrorStream)) {
if (!session.analyze(System.out)) {
return;
}
@@ -376,4 +358,8 @@ public class CompileEnvironment {
}
}
}
public boolean initializeKotlinRuntime() {
return initializeKotlinRuntime(this);
}
}
@@ -4,11 +4,12 @@ import com.google.common.base.Predicates;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import org.jetbrains.jet.JetCoreEnvironment;
import org.jetbrains.jet.codegen.ClassBuilderFactory;
import org.jetbrains.jet.codegen.ClassFileFactory;
import org.jetbrains.jet.codegen.CompilationErrorHandler;
import org.jetbrains.jet.codegen.GenerationState;
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory;
import org.jetbrains.jet.lang.psi.JetDeclaration;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetNamespace;
import org.jetbrains.jet.lang.resolve.BindingContext;
@@ -18,6 +19,7 @@ import org.jetbrains.jet.plugin.JetFileType;
import java.io.File;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
@@ -26,13 +28,13 @@ import java.util.List;
* @author yole
*/
public class CompileSession {
private final JetCoreEnvironment myEnvironment;
private final List<JetNamespace> mySourceFileNamespaces = new ArrayList<JetNamespace>();
private final List<JetNamespace> myLibrarySourceFileNamespaces = new ArrayList<JetNamespace>();
private List<String> myErrors = new ArrayList<String>();
private BindingContext myBindingContext;
private AbstractCompileEnvironment myEnvironment;
public CompileSession(JetCoreEnvironment environment) {
public CompileSession(AbstractCompileEnvironment environment) {
myEnvironment = environment;
}
@@ -50,28 +52,32 @@ public class CompileSession {
return;
}
addSources(new File(path));
addSources(new File(path), mySourceFileNamespaces);
}
private void addSources(File file) {
private void addSources(File file, List<JetNamespace> namespaces) {
if(file.isDirectory()) {
for (File child : file.listFiles()) {
addSources(child);
addSources(child, namespaces);
}
}
else {
VirtualFile fileByPath = myEnvironment.getLocalFileSystem().findFileByPath(file.getAbsolutePath());
PsiFile psiFile = PsiManager.getInstance(myEnvironment.getProject()).findFile(fileByPath);
if(psiFile instanceof JetFile) {
mySourceFileNamespaces.add(((JetFile) psiFile).getRootNamespace());
namespaces.add(((JetFile) psiFile).getRootNamespace());
}
}
}
public void addSources(VirtualFile vFile) {
addSources(vFile, mySourceFileNamespaces);
}
public void addSources(VirtualFile vFile, List<JetNamespace> namespaces) {
if (vFile.isDirectory()) {
for (VirtualFile virtualFile : vFile.getChildren()) {
addSources(virtualFile);
addSources(virtualFile, namespaces);
}
}
else {
@@ -84,10 +90,28 @@ public class CompileSession {
}
}
public void addSources(VirtualFile[] allFiles) {
for(VirtualFile vFile: allFiles) {
if (vFile.getFileType() == JetFileType.INSTANCE) {
PsiFile psiFile = PsiManager.getInstance(myEnvironment.getProject()).findFile(vFile);
if (psiFile instanceof JetFile) {
mySourceFileNamespaces.add(((JetFile) psiFile).getRootNamespace());
}
}
}
}
public List<JetNamespace> getSourceFileNamespaces() {
return mySourceFileNamespaces;
}
public BindingContext analyze() {
List<JetNamespace> allNamespaces = new ArrayList<JetNamespace>(mySourceFileNamespaces);
allNamespaces.addAll(myLibrarySourceFileNamespaces);
return AnalyzerFacade.analyzeNamespacesWithJavaIntegration(
myEnvironment.getProject(), allNamespaces, Predicates.<PsiFile>alwaysTrue(), JetControlFlowDataTraceFactory.EMPTY);
}
public boolean analyze(final PrintStream out) {
if (!myErrors.isEmpty()) {
for (String error : myErrors) {
@@ -95,18 +119,19 @@ public class CompileSession {
}
return false;
}
List<JetNamespace> allNamespaces = new ArrayList<JetNamespace>(mySourceFileNamespaces);
allNamespaces.addAll(myLibrarySourceFileNamespaces);
myBindingContext = AnalyzerFacade.analyzeNamespacesWithJavaIntegration(
myEnvironment.getProject(), allNamespaces, Predicates.<PsiFile>alwaysTrue(), JetControlFlowDataTraceFactory.EMPTY);
myBindingContext = analyze();
ErrorCollector errorCollector = new ErrorCollector(myBindingContext);
errorCollector.report(out);
return !errorCollector.hasErrors;
}
public ClassFileFactory generate() {
return generate(CompilationErrorHandler.THROW_EXCEPTION);
}
public ClassFileFactory generate(CompilationErrorHandler handler) {
GenerationState generationState = new GenerationState(myEnvironment.getProject(), ClassBuilderFactory.BINARIES);
generationState.compileCorrectNamespaces(myBindingContext, mySourceFileNamespaces);
generationState.compileCorrectNamespaces(myBindingContext, mySourceFileNamespaces, handler);
return generationState.getFactory();
}
@@ -117,16 +142,25 @@ public class CompileSession {
}
public boolean addStdLibSources() {
final File unpackedRuntimePath = CompileEnvironment.getUnpackedRuntimePath();
return addStdLibSources(false);
}
public boolean addStdLibSources(boolean forAnalize) {
/*
@todo
We add sources as library sources in case of jar
but as regular one if there is no jar
*/
final File unpackedRuntimePath = CoreCompileEnvironment.getUnpackedRuntimePath();
if (unpackedRuntimePath != null) {
addSources(new File(unpackedRuntimePath, "../../../stdlib/ktSrc").getAbsoluteFile());
addSources(new File(unpackedRuntimePath, "stdlib/ktSrc").getAbsoluteFile(), forAnalize ? myLibrarySourceFileNamespaces : mySourceFileNamespaces);
}
else {
final File runtimeJarPath = CompileEnvironment.getRuntimeJarPath();
final File runtimeJarPath = CoreCompileEnvironment.getRuntimeJarPath();
if (runtimeJarPath != null && runtimeJarPath.exists()) {
VirtualFile runtimeJar = myEnvironment.getLocalFileSystem().findFileByPath(runtimeJarPath.getAbsolutePath());
VirtualFile jarRoot = myEnvironment.getJarFileSystem().findFileByPath(runtimeJar.getPath() + "!/stdlib/ktSrc");
addSources(jarRoot);
addSources(jarRoot, myLibrarySourceFileNamespaces);
}
else {
return false;
@@ -134,4 +168,8 @@ public class CompileSession {
}
return true;
}
public List<JetNamespace> getLibrarySourceFileNamespaces() {
return myLibrarySourceFileNamespaces;
}
}
@@ -0,0 +1,84 @@
package org.jetbrains.jet.compiler;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFileSystem;
import com.intellij.util.Processor;
import jet.ExtensionFunction0;
import jet.modules.IModuleBuilder;
import jet.modules.IModuleSetBuilder;
import org.jetbrains.annotations.Nullable;
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.lang.psi.JetPsiUtil;
import org.jetbrains.jet.plugin.JetMainDetector;
import java.io.*;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.Arrays;
import java.util.List;
import java.util.jar.*;
/**
* The environment for compiling a bunch of source files or
*
* @author yole
* @author alex.tkachman
*/
public class CoreCompileEnvironment extends AbstractCompileEnvironment {
private final Disposable myRootDisposable;
private final VirtualFileSystem localFileSystem;
private VirtualFileSystem jarFileSystem;
private JetCoreEnvironment myEnvironment;
public CoreCompileEnvironment() {
myRootDisposable = new Disposable() {
@Override
public void dispose() {
}
};
myEnvironment = new JetCoreEnvironment(myRootDisposable);
localFileSystem = myEnvironment.getLocalFileSystem();
jarFileSystem = myEnvironment.getJarFileSystem();
project = myEnvironment.getProject();
}
public CoreCompileEnvironment(JetCoreEnvironment myEnvironment) {
this.myRootDisposable = null;
this.myEnvironment = myEnvironment;
localFileSystem = myEnvironment.getLocalFileSystem();
jarFileSystem = myEnvironment.getJarFileSystem();
project = myEnvironment.getProject();
}
public void dispose() {
if(myRootDisposable != null)
Disposer.dispose(myRootDisposable);
}
@Override
public void addToClasspath(File file) {
myEnvironment.addToClasspath(file);
}
@Override
public VirtualFileSystem getLocalFileSystem() {
return localFileSystem;
}
@Override
public Project getProject() {
return project;
}
@Override
public VirtualFileSystem getJarFileSystem() {
return jarFileSystem;
}
}