generate calls to functions in a Jet namespace

This commit is contained in:
Dmitry Jemerov
2011-04-14 19:39:50 +02:00
parent 91b613e8a4
commit 20520e991f
6 changed files with 91 additions and 40 deletions
@@ -7,11 +7,13 @@ import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.resolve.DescriptorUtil;
import org.objectweb.asm.Label; import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes; import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type; import org.objectweb.asm.Type;
import org.objectweb.asm.commons.InstructionAdapter; import org.objectweb.asm.commons.InstructionAdapter;
import org.objectweb.asm.commons.Method;
import java.util.List; import java.util.List;
import java.util.Stack; import java.util.Stack;
@@ -324,7 +326,8 @@ public class ExpressionCodegen extends JetVisitor {
if (callee instanceof JetSimpleNameExpression) { if (callee instanceof JetSimpleNameExpression) {
DeclarationDescriptor funDescriptor = bindingContext.resolveReferenceExpression((JetSimpleNameExpression) callee); DeclarationDescriptor funDescriptor = bindingContext.resolveReferenceExpression((JetSimpleNameExpression) callee);
if (funDescriptor instanceof FunctionDescriptor) { if (funDescriptor instanceof FunctionDescriptor) {
if (isNumberPrimitive(funDescriptor.getContainingDeclaration())) { final DeclarationDescriptor functionParent = funDescriptor.getContainingDeclaration();
if (isNumberPrimitive(functionParent)) {
if (funDescriptor.getName().equals("inv")) { if (funDescriptor.getName().equals("inv")) {
final StackValue value = myStack.pop(); // HACK we rely on the dot reference handler to put it on the stack final StackValue value = myStack.pop(); // HACK we rely on the dot reference handler to put it on the stack
final Type asmType = expressionType(expression); final Type asmType = expressionType(expression);
@@ -333,23 +336,41 @@ public class ExpressionCodegen extends JetVisitor {
return; return;
} }
} }
PsiElement declarationPsiElement = bindingContext.getDeclarationPsiElement(funDescriptor);
if (declarationPsiElement instanceof PsiMethod) {
PsiMethod method = (PsiMethod) declarationPsiElement;
pushMethodArguments(expression, method);
final boolean isStatic = method.hasModifierProperty(PsiModifier.STATIC); if (expression.getParent() instanceof JetDotQualifiedExpression) {
v.visitMethodInsn(isStatic ? Opcodes.INVOKESTATIC : Opcodes.INVOKEVIRTUAL, final JetDotQualifiedExpression parent = (JetDotQualifiedExpression) expression.getParent();
JetTypeMapper.jvmName(method.getContainingClass()), if (!resolvesToClassOrPackage(parent.getReceiverExpression())) {
method.getName(), // we have a receiver on stack
getMethodDescriptor(method)); myStack.pop().put(Type.getObjectType("java/lang/Object"), v);
final Type type = psiTypeToAsm(method.getReturnType());
if (type != Type.VOID_TYPE) {
myStack.push(StackValue.onStack(type));
} }
} }
PsiElement declarationPsiElement = bindingContext.getDeclarationPsiElement(funDescriptor);
Method methodDescriptor;
if (declarationPsiElement instanceof PsiMethod) {
PsiMethod psiMethod = (PsiMethod) declarationPsiElement;
methodDescriptor = getMethodDescriptor(psiMethod);
pushMethodArguments(expression, methodDescriptor);
final boolean isStatic = psiMethod.hasModifierProperty(PsiModifier.STATIC);
v.visitMethodInsn(isStatic ? Opcodes.INVOKESTATIC : Opcodes.INVOKEVIRTUAL,
JetTypeMapper.jvmName(psiMethod.getContainingClass()),
methodDescriptor.getName(),
methodDescriptor.getDescriptor());
}
else { else {
throw new UnsupportedOperationException("don't know how to generate call to " + declarationPsiElement); if (functionParent instanceof NamespaceDescriptor && declarationPsiElement instanceof JetFunction) {
methodDescriptor = typeMapper.mapSignature((JetFunction) declarationPsiElement);
pushMethodArguments(expression, methodDescriptor);
final String owner = NamespaceCodegen.getJVMClassName(DescriptorUtil.getFQName(functionParent));
v.invokestatic(owner, methodDescriptor.getName(), methodDescriptor.getDescriptor());
}
else {
throw new UnsupportedOperationException("don't know how to generate call to " + declarationPsiElement);
}
}
if (methodDescriptor.getReturnType() != Type.VOID_TYPE) {
myStack.push(StackValue.onStack(methodDescriptor.getReturnType()));
} }
} }
else { else {
@@ -361,24 +382,23 @@ public class ExpressionCodegen extends JetVisitor {
} }
} }
private void pushMethodArguments(JetCall expression, PsiMethod method) { private void pushMethodArguments(JetCall expression, Method method) {
PsiParameter[] parameters = method.getParameterList().getParameters(); final Type[] argTypes = method.getArgumentTypes();
List<JetArgument> args = expression.getValueArguments(); List<JetArgument> args = expression.getValueArguments();
for (int i = 0, argsSize = args.size(); i < argsSize; i++) { for (int i = 0, argsSize = args.size(); i < argsSize; i++) {
JetArgument arg = args.get(i); JetArgument arg = args.get(i);
gen(arg.getArgumentExpression(), psiTypeToAsm(parameters[i].getType())); gen(arg.getArgumentExpression(), argTypes[i]);
} }
} }
private static String getMethodDescriptor(PsiMethod method) { private static Method getMethodDescriptor(PsiMethod method) {
Type returnType = method.isConstructor() ? Type.VOID_TYPE : psiTypeToAsm(method.getReturnType()); Type returnType = method.isConstructor() ? Type.VOID_TYPE : psiTypeToAsm(method.getReturnType());
PsiParameter[] parameters = method.getParameterList().getParameters(); PsiParameter[] parameters = method.getParameterList().getParameters();
Type[] parameterTypes = new Type[parameters.length]; Type[] parameterTypes = new Type[parameters.length];
for (int i = 0; i < parameters.length; i++) { for (int i = 0; i < parameters.length; i++) {
parameterTypes[i] = psiTypeToAsm(parameters [i].getType()); parameterTypes[i] = psiTypeToAsm(parameters [i].getType());
} }
return Type.getMethodDescriptor(returnType, parameterTypes); return new Method(method.getName(), Type.getMethodDescriptor(returnType, parameterTypes));
} }
private Type expressionType(JetExpression expr) { private Type expressionType(JetExpression expr) {
@@ -798,8 +818,9 @@ public class ExpressionCodegen extends JetVisitor {
Type type = JetTypeMapper.psiClassType(javaClass); Type type = JetTypeMapper.psiClassType(javaClass);
v.anew(type); v.anew(type);
v.dup(); v.dup();
pushMethodArguments(expression, constructor); final Method constructorDescriptor = getMethodDescriptor(constructor);
v.invokespecial(JetTypeMapper.jvmName(javaClass), "<init>", getMethodDescriptor(constructor)); pushMethodArguments(expression, constructorDescriptor);
v.invokespecial(JetTypeMapper.jvmName(javaClass), "<init>", constructorDescriptor.getDescriptor());
myStack.push(StackValue.onStack(type)); myStack.push(StackValue.onStack(type));
return; return;
} }
@@ -36,22 +36,7 @@ public class FunctionCodegen {
} }
private void gen(JetFunction f) { private void gen(JetFunction f) {
final List<JetParameter> parameters = f.getValueParameters(); Method method = typeMapper.mapSignature(f);
Type[] parameterTypes = new Type[parameters.size()];
for (int i = 0; i < parameters.size(); i++) {
parameterTypes[i] = typeMapper.mapType(bindingContext.resolveTypeReference(parameters.get(i).getTypeReference()));
}
final JetTypeReference returnTypeRef = f.getReturnTypeRef();
Type returnType;
if (returnTypeRef == null) {
final FunctionDescriptor functionDescriptor = bindingContext.getFunctionDescriptor(f);
final JetType type = functionDescriptor.getUnsubstitutedReturnType();
returnType = typeMapper.mapType(type);
}
else {
returnType = typeMapper.mapType(bindingContext.resolveTypeReference(returnTypeRef));
}
Method method = new Method(f.getName(), returnType, parameterTypes);
final MethodVisitor mv = v.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, final MethodVisitor mv = v.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
method.getName(), method.getDescriptor(), null, null); method.getName(), method.getDescriptor(), null, null);
mv.visitCode(); mv.visitCode();
@@ -60,12 +45,13 @@ public class FunctionCodegen {
List<ValueParameterDescriptor> parameDescrs = bindingContext.getFunctionDescriptor(f).getUnsubstitutedValueParameters(); List<ValueParameterDescriptor> parameDescrs = bindingContext.getFunctionDescriptor(f).getUnsubstitutedValueParameters();
Type[] argTypes = method.getArgumentTypes();
for (int i = 0; i < parameDescrs.size(); i++) { for (int i = 0; i < parameDescrs.size(); i++) {
ValueParameterDescriptor parameter = parameDescrs.get(i); ValueParameterDescriptor parameter = parameDescrs.get(i);
frameMap.enter(parameter, parameterTypes[i].getSize()); frameMap.enter(parameter, argTypes[i].getSize());
} }
ExpressionCodegen codegen = new ExpressionCodegen(mv, bindingContext, frameMap, typeMapper, returnType); ExpressionCodegen codegen = new ExpressionCodegen(mv, bindingContext, frameMap, typeMapper, method.getReturnType());
bodyExpression.accept(codegen); bodyExpression.accept(codegen);
generateReturn(mv, bodyExpression, codegen); generateReturn(mv, bodyExpression, codegen);
mv.visitMaxs(0, 0); mv.visitMaxs(0, 0);
@@ -2,9 +2,15 @@ package org.jetbrains.jet.codegen;
import com.intellij.psi.PsiClass; import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import org.jetbrains.jet.lang.psi.JetFunction;
import org.jetbrains.jet.lang.psi.JetParameter;
import org.jetbrains.jet.lang.psi.JetTypeReference;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lang.types.*;
import org.objectweb.asm.Type; import org.objectweb.asm.Type;
import org.objectweb.asm.commons.Method;
import java.util.List;
/** /**
* @author yole * @author yole
@@ -105,4 +111,23 @@ public class JetTypeMapper {
throw new UnsupportedOperationException("Unknown type " + jetType); throw new UnsupportedOperationException("Unknown type " + jetType);
} }
public Method mapSignature(JetFunction f) {
final List<JetParameter> parameters = f.getValueParameters();
Type[] parameterTypes = new Type[parameters.size()];
for (int i = 0; i < parameters.size(); i++) {
parameterTypes[i] = mapType(bindingContext.resolveTypeReference(parameters.get(i).getTypeReference()));
}
final JetTypeReference returnTypeRef = f.getReturnTypeRef();
Type returnType;
if (returnTypeRef == null) {
final FunctionDescriptor functionDescriptor = bindingContext.getFunctionDescriptor(f);
final JetType type = functionDescriptor.getUnsubstitutedReturnType();
returnType = mapType(type);
}
else {
returnType = mapType(bindingContext.resolveTypeReference(returnTypeRef));
}
return new Method(f.getName(), returnType, parameterTypes);
}
} }
@@ -54,6 +54,9 @@ public class NamespaceCodegen {
} }
public static String getJVMClassName(String fqName) { public static String getJVMClassName(String fqName) {
if (fqName.length() == 0) {
return "namespace";
}
return fqName.replace('.', '/') + "/namespace"; return fqName.replace('.', '/') + "/namespace";
} }
+9
View File
@@ -0,0 +1,9 @@
fun f() {
val x = new StringBuilder();
g(x);
return x.toString();
}
fun g(sb: StringBuilder): Unit {
sb.append("foo");
}
@@ -530,6 +530,13 @@ public class NamespaceGenTest extends LightCodeInsightFixtureTestCase {
assertEquals(Boolean.FALSE, main.invoke(null, null, "jet")); assertEquals(Boolean.FALSE, main.invoke(null, null, "jet"));
} }
public void testFunctionCall() throws Exception {
loadFile("functionCall.jet");
System.out.println(generateToText());
final Method main = generateFunction();
assertEquals("foo", main.invoke(null));
}
private void binOpTest(final String text, final Object arg1, final Object arg2, final Object expected) throws Exception { private void binOpTest(final String text, final Object arg1, final Object arg2, final Object expected) throws Exception {
loadText(text); loadText(text);
System.out.println(generateToText()); System.out.println(generateToText());