diff --git a/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java b/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java new file mode 100644 index 00000000000..74dc8a95207 --- /dev/null +++ b/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java @@ -0,0 +1,65 @@ +package org.jetbrains.jet.codegen; + +import com.intellij.openapi.project.Project; +import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.types.ClassDescriptor; +import org.jetbrains.jet.lang.types.JetStandardLibrary; +import org.jetbrains.jet.lang.types.JetType; +import org.objectweb.asm.ClassVisitor; + +import java.util.List; + +/** + * @author max + */ +public class ClassCodegen { + private final Project project; + private final ClassVisitor v; + private final BindingContext bindingContext; + + public ClassCodegen(Project project, Codegens v, JetClass jetClass, BindingContext bindingContext) { + this.project = project; + this.v = null; + this.bindingContext = bindingContext; + + ClassDescriptor descriptor = bindingContext.getClassDescriptor(jetClass); + String fqName = CodeGenUtil.getInternalInterfaceName(descriptor); + + List delegationSpecifiers = jetClass.getDelegationSpecifiers(); + for (JetDelegationSpecifier specifier : delegationSpecifiers) { + JetType superType = bindingContext.resolveTypeReference(specifier.getTypeReference()); + String superClassFQN = CodeGenUtil.getInternalInterfaceName((ClassDescriptor) superType.getConstructor().getDeclarationDescriptor()); + } + //descriptor. + +/* + v.visit(Opcodes.V1_6, + Opcodes.ACC_PUBLIC, + fqName.replace('.', '/'), + null, + //"jet/lang/Namespace", + "java/lang/Object", + new String[0] + ); +*/ + } + + public void generate(JetNamespace namespace) { + 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) { + propertyCodegen.gen((JetProperty) declaration, namespace); + } + else if (declaration instanceof JetFunction) { + functionCodegen.gen((JetFunction) declaration, namespace); + } + } + } + + public ClassVisitor getVisitor() { + return v; + } +} diff --git a/idea/src/org/jetbrains/jet/codegen/ClassVisitorFactory.java b/idea/src/org/jetbrains/jet/codegen/ClassVisitorFactory.java deleted file mode 100644 index 40ff59f7c38..00000000000 --- a/idea/src/org/jetbrains/jet/codegen/ClassVisitorFactory.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.jetbrains.jet.codegen; - -import org.jetbrains.jet.lang.psi.JetNamespace; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.util.TraceClassVisitor; - -import java.io.PrintWriter; -import java.io.StringWriter; - -/** - * @author max - */ -public class ClassVisitorFactory { - public ClassVisitor visitorForClassIn(JetNamespace namespace) { - return new TraceClassVisitor(new PrintWriter(new StringWriter())); - } -} diff --git a/idea/src/org/jetbrains/jet/codegen/CodeGenUtil.java b/idea/src/org/jetbrains/jet/codegen/CodeGenUtil.java new file mode 100644 index 00000000000..be0ffdae816 --- /dev/null +++ b/idea/src/org/jetbrains/jet/codegen/CodeGenUtil.java @@ -0,0 +1,21 @@ +package org.jetbrains.jet.codegen; + +import org.jetbrains.jet.lang.types.ClassDescriptor; +import org.jetbrains.jet.resolve.DescriptorUtil; + +/** + * @author max + */ +public class CodeGenUtil { + public static String getInternalInterfaceName(ClassDescriptor descriptor) { + return DescriptorUtil.getFQName(descriptor).replace('.', '/'); + } + + public static String getInternalImplementationName(ClassDescriptor descriptor) { + return getInternalInterfaceName(descriptor) + "$$Impl"; + } + + public static String getInternalDelegatingImplementationName(ClassDescriptor descriptor) { + return getInternalInterfaceName(descriptor) + "$$DImpl"; + } +} diff --git a/idea/src/org/jetbrains/jet/codegen/Codegens.java b/idea/src/org/jetbrains/jet/codegen/Codegens.java new file mode 100644 index 00000000000..97c29c9a98e --- /dev/null +++ b/idea/src/org/jetbrains/jet/codegen/Codegens.java @@ -0,0 +1,91 @@ +package org.jetbrains.jet.codegen; + +import com.intellij.openapi.project.Project; +import org.jetbrains.jet.lang.psi.JetNamespace; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.util.TraceClassVisitor; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author max + */ +public class Codegens { + private final Project project; + private final boolean isText; + private final Map ns2codegen = new HashMap(); + private final Map generators = new HashMap(); + private boolean isDone = false; + + public Codegens(Project project, boolean text) { + this.project = project; + isText = text; + } + + public ClassVisitor newVisitor(String filePath) { + ClassVisitor visitor; + if (isText) { + visitor = new TraceClassVisitor(new PrintWriter(new StringWriter())); + } + else { + visitor = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); + } + + generators.put(filePath, visitor); + return visitor; + } + + public NamespaceCodegen forNamespace(JetNamespace namespace) { + assert !isDone : "Already done!"; + String fqName = namespace.getFQName(); + NamespaceCodegen codegen = ns2codegen.get(fqName); + if (codegen == null) { + codegen = new NamespaceCodegen(project, newVisitor(NamespaceCodegen.getJVMClassName(fqName) + ".class"), fqName); + ns2codegen.put(fqName, codegen); + } + + return codegen; + } + + private void done() { + if (!isDone) { + isDone = true; + for (NamespaceCodegen codegen : ns2codegen.values()) { + codegen.done(); + } + } + } + + public String asText(String file) { + assert isText : "Need to create with text=true"; + + done(); + + TraceClassVisitor visitor = (TraceClassVisitor) generators.get(file); + + StringWriter writer = new StringWriter(); + visitor.print(new PrintWriter(writer)); + + return writer.toString(); + } + + public byte[] asBytes(String file) { + assert !isText : "This is debug stuff, only produces texts."; + + done(); + + ClassWriter visitor = (ClassWriter) generators.get(file); + return visitor.toByteArray(); + } + + public List files() { + done(); + return new ArrayList(generators.keySet()); + } +} diff --git a/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java b/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java index 4945f158c96..150c6ab40e9 100644 --- a/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java @@ -28,6 +28,14 @@ public class FunctionCodegen { } public void gen(JetFunction f, JetNamespace owner) { + gen(f); + } + + public void gen(JetFunction f, JetClass owner) { + + } + + private void gen(JetFunction f) { final List parameters = f.getValueParameters(); Type[] parameterTypes = new Type[parameters.size()]; for (int i = 0; i < parameters.size(); i++) { @@ -83,8 +91,4 @@ public class FunctionCodegen { } return false; } - - public void gen(JetFunction f, JetClass owner) { - - } } diff --git a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java index 1b1abb1c0b5..588d4b85ed8 100644 --- a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -83,18 +83,9 @@ public class JetTypeMapper { } if (descriptor instanceof ClassDescriptor) { - return Type.getObjectType(getFQName(descriptor).replace('.', '/')); + return Type.getObjectType(CodeGenUtil.getInternalInterfaceName((ClassDescriptor) descriptor)); } throw new UnsupportedOperationException("Unknown type " + jetType); } - - private static String getFQName(DeclarationDescriptor descriptor) { - DeclarationDescriptor container = descriptor.getContainingDeclaration(); - if (container != null && !(container instanceof ModuleDescriptor)) { - return getFQName(container) + "." + descriptor.getName(); - } - - return descriptor.getName(); - } } diff --git a/idea/src/org/jetbrains/jet/compiler/JetCompiler.java b/idea/src/org/jetbrains/jet/compiler/JetCompiler.java index a071d196147..f242113cd88 100644 --- a/idea/src/org/jetbrains/jet/compiler/JetCompiler.java +++ b/idea/src/org/jetbrains/jet/compiler/JetCompiler.java @@ -12,15 +12,16 @@ 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.Codegens; 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.List; import java.util.Map; /** @@ -64,7 +65,7 @@ public class JetCompiler implements TranslatingCompiler { } private static class ModuleCompileState { - private final Map ns2codegen = new HashMap(); + private final Codegens codegens; private final CompileContext compileContext; private final Module module; private final OutputSink outputSink; @@ -73,6 +74,7 @@ public class JetCompiler implements TranslatingCompiler { this.compileContext = compileContext; this.module = module; this.outputSink = outputSink; + codegens = new Codegens(compileContext.getProject(), false); } public void compile(final VirtualFile virtualFile) { @@ -82,13 +84,7 @@ public class JetCompiler implements TranslatingCompiler { 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); - } + NamespaceCodegen codegen = codegens.forNamespace(namespace); codegen.generate(namespace); } } @@ -97,28 +93,15 @@ public class JetCompiler implements TranslatingCompiler { public void done() { VirtualFile outputDir = compileContext.getModuleOutputDirectory(module); - - for (Map.Entry entry : ns2codegen.entrySet()) { - NamespaceCodegen codegen = entry.getValue(); - codegen.done(); - + List files = codegens.files(); + for (String file : files) { + File target = new File(outputDir.getPath(), file); try { - File nsOutputDir = dirForPackage(outputDir, entry.getKey()); - ClassWriter writer = (ClassWriter) codegen.getVisitor(); - File output = new File(nsOutputDir, "namespace.class"); - FileUtil.writeToFile(output, writer.toByteArray()); + FileUtil.writeToFile(target, codegens.asBytes(file)); } 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.exists() && !result.mkdirs()) { - throw new IOException("Failed to create directory for package"); - } - return result; - } } } diff --git a/idea/src/org/jetbrains/jet/resolve/DescriptorUtil.java b/idea/src/org/jetbrains/jet/resolve/DescriptorUtil.java index 13329b1524c..895fa2beb95 100644 --- a/idea/src/org/jetbrains/jet/resolve/DescriptorUtil.java +++ b/idea/src/org/jetbrains/jet/resolve/DescriptorUtil.java @@ -125,4 +125,13 @@ public class DescriptorUtil { } } } + + public static String getFQName(DeclarationDescriptor descriptor) { + DeclarationDescriptor container = descriptor.getContainingDeclaration(); + if (container != null && !(container instanceof ModuleDescriptor)) { + return getFQName(container) + "." + descriptor.getName(); + } + + return descriptor.getName(); + } } diff --git a/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java b/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java index da92859e461..1b1361450cb 100644 --- a/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java @@ -8,13 +8,10 @@ import org.jetbrains.jet.lang.JetFileType; import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.psi.JetNamespace; import org.jetbrains.jet.parsing.JetParsingTest; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.util.TraceClassVisitor; -import java.io.PrintWriter; -import java.io.StringWriter; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.List; /** * @author yole @@ -497,29 +494,31 @@ public class NamespaceGenTest extends LightCodeInsightFixtureTestCase { } private String generateToText() { - StringWriter writer = new StringWriter(); + Codegens state = new Codegens(getProject(), true); JetFile jetFile = (JetFile) myFixture.getFile(); JetNamespace namespace = jetFile.getRootNamespace(); - NamespaceCodegen codegen = new NamespaceCodegen(getProject(), - new TraceClassVisitor(new PrintWriter(writer)), - namespace.getFQName()); + NamespaceCodegen codegen = state.forNamespace(namespace); codegen.generate(namespace); - codegen.done(); - return writer.toString(); + + List files = state.files(); + assertEquals("This test only supposed to generate single class file", 1, files.size()); + + return state.asText(files.get(0)); } private Class generateToClass() { + Codegens state = new Codegens(getProject(), false); JetFile jetFile = (JetFile) myFixture.getFile(); - ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); final JetNamespace namespace = jetFile.getRootNamespace(); - NamespaceCodegen codegen = new NamespaceCodegen(getProject(), - writer, - namespace.getFQName()); + + NamespaceCodegen codegen = state.forNamespace(namespace); codegen.generate(namespace); - final byte[] data = writer.toByteArray(); + + List files = state.files(); + assertEquals("This test only supposed to generate single class file", 1, files.size()); + final byte[] data = state.asBytes(files.get(0)); MyClassLoader classLoader = new MyClassLoader(NamespaceGenTest.class.getClassLoader()); - final Class aClass = classLoader.doDefineClass(NamespaceCodegen.getJVMClassName(namespace.getFQName()).replace("/", "."), data); - return aClass; + return classLoader.doDefineClass(NamespaceCodegen.getJVMClassName(namespace.getFQName()).replace("/", "."), data); } private Method generateFunction() {