Jet files can be compiled from within IDEA
This commit is contained in:
@@ -5,11 +5,12 @@
|
||||
<vendor>JetBrains</vendor>
|
||||
|
||||
<application-components>
|
||||
<!-- Add your application components here -->
|
||||
</application-components>
|
||||
|
||||
<project-components>
|
||||
<!-- Add your project components here -->
|
||||
<component>
|
||||
<implementation-class>org.jetbrains.jet.compiler.JetCompilerManager</implementation-class>
|
||||
</component>
|
||||
</project-components>
|
||||
|
||||
<actions>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Module> moduleChunk, VirtualFile[] virtualFiles, OutputSink outputSink) {
|
||||
Map<Module, ModuleCompileState> moduleMap = new HashMap<Module, ModuleCompileState>();
|
||||
|
||||
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<String, NamespaceCodegen> ns2codegen = new HashMap<String, NamespaceCodegen>();
|
||||
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<String, NamespaceCodegen> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.<FileType>singleton(JetFileType.INSTANCE),
|
||||
Collections.singleton(StdFileTypes.CLASS));
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user