Jet files can be compiled from within IDEA
This commit is contained in:
@@ -5,11 +5,12 @@
|
|||||||
<vendor>JetBrains</vendor>
|
<vendor>JetBrains</vendor>
|
||||||
|
|
||||||
<application-components>
|
<application-components>
|
||||||
<!-- Add your application components here -->
|
|
||||||
</application-components>
|
</application-components>
|
||||||
|
|
||||||
<project-components>
|
<project-components>
|
||||||
<!-- Add your project components here -->
|
<component>
|
||||||
|
<implementation-class>org.jetbrains.jet.compiler.JetCompilerManager</implementation-class>
|
||||||
|
</component>
|
||||||
</project-components>
|
</project-components>
|
||||||
|
|
||||||
<actions>
|
<actions>
|
||||||
|
|||||||
@@ -16,22 +16,28 @@ import org.objectweb.asm.Opcodes;
|
|||||||
* @author max
|
* @author max
|
||||||
*/
|
*/
|
||||||
public class NamespaceCodegen {
|
public class NamespaceCodegen {
|
||||||
public NamespaceCodegen() {
|
private final Project project;
|
||||||
}
|
private final ClassVisitor v;
|
||||||
|
|
||||||
public void generate(JetNamespace namespace, ClassVisitor v, Project project) {
|
public NamespaceCodegen(Project project, ClassVisitor v, String fqName) {
|
||||||
BindingContext bindingContext = AnalyzingUtils.analyzeNamespace(namespace, ErrorHandler.THROW_EXCEPTION);
|
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,
|
v.visit(Opcodes.V1_6,
|
||||||
Opcodes.ACC_PUBLIC,
|
Opcodes.ACC_PUBLIC,
|
||||||
getJVMClassName(namespace),
|
getJVMClassName(fqName),
|
||||||
null,
|
null,
|
||||||
//"jet/lang/Namespace",
|
//"jet/lang/Namespace",
|
||||||
"java/lang/Object",
|
"java/lang/Object",
|
||||||
new String[0]
|
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()) {
|
for (JetDeclaration declaration : namespace.getDeclarations()) {
|
||||||
if (declaration instanceof JetProperty) {
|
if (declaration instanceof JetProperty) {
|
||||||
@@ -41,12 +47,17 @@ public class NamespaceCodegen {
|
|||||||
functionCodegen.gen((JetFunction) declaration, namespace);
|
functionCodegen.gen((JetFunction) declaration, namespace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void done() {
|
||||||
v.visitEnd();
|
v.visitEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getJVMClassName(JetNamespace namespace) {
|
public static String getJVMClassName(String fqName) {
|
||||||
return namespace.getFQName().replace('.', '/') + "/namespace";
|
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
|
* @author yole
|
||||||
*/
|
*/
|
||||||
public class NamespaceGenTest extends LightCodeInsightFixtureTestCase {
|
public class NamespaceGenTest extends LightCodeInsightFixtureTestCase {
|
||||||
private NamespaceCodegen codegen;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setUp() throws Exception {
|
protected void setUp() throws Exception {
|
||||||
super.setUp();
|
super.setUp();
|
||||||
codegen = new NamespaceCodegen();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testPSVM() throws Exception {
|
public void testPSVM() throws Exception {
|
||||||
@@ -114,7 +111,10 @@ public class NamespaceGenTest extends LightCodeInsightFixtureTestCase {
|
|||||||
StringWriter writer = new StringWriter();
|
StringWriter writer = new StringWriter();
|
||||||
JetFile jetFile = (JetFile) myFixture.getFile();
|
JetFile jetFile = (JetFile) myFixture.getFile();
|
||||||
JetNamespace namespace = jetFile.getRootNamespace();
|
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();
|
return writer.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,10 +122,13 @@ public class NamespaceGenTest extends LightCodeInsightFixtureTestCase {
|
|||||||
JetFile jetFile = (JetFile) myFixture.getFile();
|
JetFile jetFile = (JetFile) myFixture.getFile();
|
||||||
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
|
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
|
||||||
final JetNamespace namespace = jetFile.getRootNamespace();
|
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();
|
final byte[] data = writer.toByteArray();
|
||||||
MyClassLoader classLoader = new MyClassLoader(NamespaceGenTest.class.getClassLoader());
|
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;
|
return aClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user