diff --git a/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java b/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java index 773085e52fb..2877de3c99c 100644 --- a/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java @@ -1,9 +1,13 @@ package org.jetbrains.jet.codegen; -import org.jetbrains.jet.lang.psi.JetClass; -import org.jetbrains.jet.lang.psi.JetFunction; -import org.jetbrains.jet.lang.psi.JetNamespace; +import org.jetbrains.jet.lang.psi.*; import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; +import org.objectweb.asm.commons.Method; + +import java.util.List; /** * @author max @@ -16,7 +20,42 @@ public class FunctionCodegen { } public void gen(JetFunction f, JetNamespace owner) { + final List parameters = f.getValueParameters(); + Type[] parameterTypes = new Type[parameters.size()]; + for (int i = 0; i < parameters.size(); i++) { + parameterTypes[i] = mapTypeReference(parameters.get(i).getTypeReference()); + } + Method method = new Method(f.getName(), Type.VOID_TYPE, parameterTypes); + final MethodVisitor mv = v.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, + method.getName(), method.getDescriptor(), null, null); + mv.visitCode(); + mv.visitInsn(Opcodes.RETURN); + mv.visitEnd(); + } + private Type mapTypeReference(JetTypeReference typeRef) { + if (typeRef == null) { + throw new UnsupportedOperationException("Cannot evaluate type for parameter with no type ref"); + } + final JetTypeElement typeElement = typeRef.getTypeElement(); + if (typeElement instanceof JetUserType) { + final String referencedName = ((JetUserType) typeElement).getReferencedName(); + if ("Array".equals(referencedName)) { + final List typeArguments = ((JetUserType) typeElement).getTypeArguments(); + if (typeArguments.size() != 1) { + throw new UnsupportedOperationException("arrays must have one type argument"); + } + final JetTypeReference elementTypeRef = typeArguments.get(0).getTypeReference(); + Type elementType = mapTypeReference(elementTypeRef); + return Type.getType("[" + elementType.getDescriptor()); + } + + if ("String".equals(referencedName)) { + return Type.getType(String.class); + } + } + + throw new UnsupportedOperationException("Unknown type " + typeRef); } public void gen(JetFunction f, JetClass owner) { diff --git a/idea/src/org/jetbrains/jet/codegen/NamespaceCodegen.java b/idea/src/org/jetbrains/jet/codegen/NamespaceCodegen.java index aba2c042338..9c745e5186e 100644 --- a/idea/src/org/jetbrains/jet/codegen/NamespaceCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/NamespaceCodegen.java @@ -19,9 +19,10 @@ public class NamespaceCodegen { final FunctionCodegen functionCodegen = new FunctionCodegen(v); v.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC, - namespace.getFQName().replace('.', '/') + "/namespace", + getJVMClassName(namespace), null, - "jet/lang/Namespace", + //"jet/lang/Namespace", + "java/lang/Object", new String[0] ); @@ -37,4 +38,8 @@ public class NamespaceCodegen { v.visitEnd(); } + + public static String getJVMClassName(JetNamespace namespace) { + return namespace.getFQName().replace('.', '/') + "/namespace"; + } } diff --git a/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java b/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java index 95a0b2c5d22..52ec8e0378d 100644 --- a/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java @@ -4,21 +4,60 @@ import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; 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; /** * @author yole */ public class NamespaceGenTest extends LightCodeInsightFixtureTestCase { - public void testPSVM() { + public void testPSVM() throws InvocationTargetException, IllegalAccessException { myFixture.configureByFile(JetParsingTest.getTestDataDir() + "/codegen/PSVM.jet"); JetFile jetFile = (JetFile) myFixture.getFile(); JetNamespace namespace = jetFile.getRootNamespace(); NamespaceCodegen codegen = new NamespaceCodegen(); + final String text = generateToText(namespace, codegen); + System.out.println(text); + + final Class aClass = generateToClass(namespace, codegen); + final Method[] methods = aClass.getMethods(); + final Method main = methods[0]; + Object[] args = new Object[] { new String[0] }; + main.invoke(null, args); + } + + private static String generateToText(JetNamespace namespace, NamespaceCodegen codegen) { StringWriter writer = new StringWriter(); codegen.generate(namespace, new TraceClassVisitor(new PrintWriter(writer))); + return writer.toString(); + } + + private static Class generateToClass(JetNamespace namespace, NamespaceCodegen codegen) { + ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); + codegen.generate(namespace, writer); + final byte[] data = writer.toByteArray(); + MyClassLoader classLoader = new MyClassLoader(NamespaceGenTest.class.getClassLoader()); + final Class aClass = classLoader.doDefineClass(NamespaceCodegen.getJVMClassName(namespace).replace("/", "."), data); + return aClass; + } + + private static class MyClassLoader extends ClassLoader { + public MyClassLoader(ClassLoader parent) { + super(parent); + } + + public Class doDefineClass(String name, byte[] data) { + return defineClass(name, data, 0, data.length); + } + + @Override + public Class loadClass(String name) throws ClassNotFoundException { + return super.loadClass(name); + } } }