diff --git a/idea/META-INF/plugin.xml b/idea/META-INF/plugin.xml index d06ca31e619..66c13c395b7 100644 --- a/idea/META-INF/plugin.xml +++ b/idea/META-INF/plugin.xml @@ -5,11 +5,12 @@ JetBrains - - + + org.jetbrains.jet.compiler.JetCompilerManager + diff --git a/idea/src/org/jetbrains/jet/codegen/NamespaceCodegen.java b/idea/src/org/jetbrains/jet/codegen/NamespaceCodegen.java index 15f6a76cad1..9cd32a6711c 100644 --- a/idea/src/org/jetbrains/jet/codegen/NamespaceCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/NamespaceCodegen.java @@ -16,22 +16,28 @@ import org.objectweb.asm.Opcodes; * @author max */ public class NamespaceCodegen { - public NamespaceCodegen() { - } + private final Project project; + private final ClassVisitor v; - public void generate(JetNamespace namespace, ClassVisitor v, Project project) { - BindingContext bindingContext = AnalyzingUtils.analyzeNamespace(namespace, ErrorHandler.THROW_EXCEPTION); + public NamespaceCodegen(Project project, ClassVisitor v, String fqName) { + this.project = project; + this.v = v; - final PropertyCodegen propertyCodegen = new PropertyCodegen(v); - final FunctionCodegen functionCodegen = new FunctionCodegen(v, JetStandardLibrary.getJetStandardLibrary(project), bindingContext); v.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC, - getJVMClassName(namespace), + getJVMClassName(fqName), null, //"jet/lang/Namespace", "java/lang/Object", new String[0] ); + } + + public void generate(JetNamespace namespace) { + BindingContext bindingContext = AnalyzingUtils.analyzeNamespace(namespace, ErrorHandler.THROW_EXCEPTION); + + final PropertyCodegen propertyCodegen = new PropertyCodegen(v); + final FunctionCodegen functionCodegen = new FunctionCodegen(v, JetStandardLibrary.getJetStandardLibrary(project), bindingContext); for (JetDeclaration declaration : namespace.getDeclarations()) { if (declaration instanceof JetProperty) { @@ -41,12 +47,17 @@ public class NamespaceCodegen { functionCodegen.gen((JetFunction) declaration, namespace); } } + } - + public void done() { v.visitEnd(); } - public static String getJVMClassName(JetNamespace namespace) { - return namespace.getFQName().replace('.', '/') + "/namespace"; + public static String getJVMClassName(String fqName) { + return fqName.replace('.', '/') + "/namespace"; + } + + public ClassVisitor getVisitor() { + return v; } } diff --git a/idea/src/org/jetbrains/jet/compiler/JetCompiler.java b/idea/src/org/jetbrains/jet/compiler/JetCompiler.java new file mode 100644 index 00000000000..e5fa803f0e9 --- /dev/null +++ b/idea/src/org/jetbrains/jet/compiler/JetCompiler.java @@ -0,0 +1,124 @@ +package org.jetbrains.jet.compiler; + +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.compiler.CompileContext; +import com.intellij.openapi.compiler.CompileScope; +import com.intellij.openapi.compiler.CompilerMessageCategory; +import com.intellij.openapi.compiler.TranslatingCompiler; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiManager; +import com.intellij.util.Chunk; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.codegen.NamespaceCodegen; +import org.jetbrains.jet.lang.JetFileType; +import org.jetbrains.jet.lang.psi.JetFile; +import org.jetbrains.jet.lang.psi.JetNamespace; +import org.objectweb.asm.ClassWriter; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +/** + * @author yole + */ +public class JetCompiler implements TranslatingCompiler { + @Override + public boolean isCompilableFile(VirtualFile virtualFile, CompileContext compileContext) { + return virtualFile.getFileType() instanceof JetFileType; + } + + @NotNull + @Override + public String getDescription() { + return "Jet Language Compiler"; + } + + @Override + public boolean validateConfiguration(CompileScope compileScope) { + return true; + } + + @Override + public void compile(CompileContext compileContext, Chunk moduleChunk, VirtualFile[] virtualFiles, OutputSink outputSink) { + Map moduleMap = new HashMap(); + + for (VirtualFile virtualFile : virtualFiles) { + Module module = compileContext.getModuleByFile(virtualFile); + ModuleCompileState state = moduleMap.get(module); + if (state == null) { + state = new ModuleCompileState(compileContext, module, outputSink); + moduleMap.put(module, state); + } + state.compile(virtualFile); + } + + for (ModuleCompileState state : moduleMap.values()) { + state.done(); + } + + } + + private static class ModuleCompileState { + private final Map ns2codegen = new HashMap(); + private final CompileContext compileContext; + private final Module module; + private final OutputSink outputSink; + + public ModuleCompileState(CompileContext compileContext, Module module, OutputSink outputSink) { + this.compileContext = compileContext; + this.module = module; + this.outputSink = outputSink; + } + + public void compile(final VirtualFile virtualFile) { + ApplicationManager.getApplication().runReadAction(new Runnable() { + @Override + public void run() { + PsiFile psiFile = PsiManager.getInstance(module.getProject()).findFile(virtualFile); + if (psiFile instanceof JetFile) { + final JetNamespace namespace = ((JetFile) psiFile).getRootNamespace(); + String fqName = namespace.getFQName(); + NamespaceCodegen codegen = ns2codegen.get(fqName); + if (codegen == null) { + ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); + codegen = new NamespaceCodegen(compileContext.getProject(), writer, fqName); + ns2codegen.put(fqName, codegen); + } + codegen.generate(namespace); + } + } + }); + } + + public void done() { + VirtualFile outputDir = compileContext.getModuleOutputDirectory(module); + + for (Map.Entry entry : ns2codegen.entrySet()) { + NamespaceCodegen codegen = entry.getValue(); + codegen.done(); + + try { + File nsOutputDir = dirForPackage(outputDir, entry.getKey()); + ClassWriter writer = (ClassWriter) codegen.getVisitor(); + File output = new File(nsOutputDir, "namespace.class"); + FileUtil.writeToFile(output, writer.toByteArray()); + } catch (IOException e) { + compileContext.addMessage(CompilerMessageCategory.ERROR, e.getMessage(), null, 0, 0); + } + } + } + + private static File dirForPackage(VirtualFile root, String fqName) throws IOException { + File result = new File(root.getPath(), fqName.replace(".", "/")); + if (!result.mkdirs()) { + throw new IOException("Failed to create directory for package"); + } + return result; + } + } +} diff --git a/idea/src/org/jetbrains/jet/compiler/JetCompilerManager.java b/idea/src/org/jetbrains/jet/compiler/JetCompilerManager.java new file mode 100644 index 00000000000..26eff803644 --- /dev/null +++ b/idea/src/org/jetbrains/jet/compiler/JetCompilerManager.java @@ -0,0 +1,19 @@ +package org.jetbrains.jet.compiler; + +import com.intellij.openapi.compiler.CompilerManager; +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.fileTypes.StdFileTypes; +import org.jetbrains.jet.lang.JetFileType; + +import java.util.Collections; + +/** + * @author yole + */ +public class JetCompilerManager { + public JetCompilerManager(CompilerManager manager) { + manager.addTranslatingCompiler(new JetCompiler(), + Collections.singleton(JetFileType.INSTANCE), + Collections.singleton(StdFileTypes.CLASS)); + } +} diff --git a/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java b/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java index a46788c8562..4db4c157451 100644 --- a/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java @@ -18,12 +18,9 @@ import java.lang.reflect.Method; * @author yole */ public class NamespaceGenTest extends LightCodeInsightFixtureTestCase { - private NamespaceCodegen codegen; - @Override protected void setUp() throws Exception { super.setUp(); - codegen = new NamespaceCodegen(); } public void testPSVM() throws Exception { @@ -114,7 +111,10 @@ public class NamespaceGenTest extends LightCodeInsightFixtureTestCase { StringWriter writer = new StringWriter(); JetFile jetFile = (JetFile) myFixture.getFile(); JetNamespace namespace = jetFile.getRootNamespace(); - codegen.generate(namespace, new TraceClassVisitor(new PrintWriter(writer)), getProject()); + NamespaceCodegen codegen = new NamespaceCodegen(getProject(), + new TraceClassVisitor(new PrintWriter(writer)), + namespace.getFQName()); + codegen.generate(namespace); return writer.toString(); } @@ -122,10 +122,13 @@ public class NamespaceGenTest extends LightCodeInsightFixtureTestCase { JetFile jetFile = (JetFile) myFixture.getFile(); ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); final JetNamespace namespace = jetFile.getRootNamespace(); - codegen.generate(namespace, writer, getProject()); + NamespaceCodegen codegen = new NamespaceCodegen(getProject(), + writer, + namespace.getFQName()); + codegen.generate(namespace); final byte[] data = writer.toByteArray(); MyClassLoader classLoader = new MyClassLoader(NamespaceGenTest.class.getClassLoader()); - final Class aClass = classLoader.doDefineClass(NamespaceCodegen.getJVMClassName(namespace).replace("/", "."), data); + final Class aClass = classLoader.doDefineClass(NamespaceCodegen.getJVMClassName(namespace.getFQName()).replace("/", "."), data); return aClass; }