generate calls to functions in a Jet namespace
This commit is contained in:
@@ -7,11 +7,13 @@ import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.types.*;
|
||||
import org.jetbrains.jet.lexer.JetTokens;
|
||||
import org.jetbrains.jet.resolve.DescriptorUtil;
|
||||
import org.objectweb.asm.Label;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.commons.InstructionAdapter;
|
||||
import org.objectweb.asm.commons.Method;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
@@ -324,7 +326,8 @@ public class ExpressionCodegen extends JetVisitor {
|
||||
if (callee instanceof JetSimpleNameExpression) {
|
||||
DeclarationDescriptor funDescriptor = bindingContext.resolveReferenceExpression((JetSimpleNameExpression) callee);
|
||||
if (funDescriptor instanceof FunctionDescriptor) {
|
||||
if (isNumberPrimitive(funDescriptor.getContainingDeclaration())) {
|
||||
final DeclarationDescriptor functionParent = funDescriptor.getContainingDeclaration();
|
||||
if (isNumberPrimitive(functionParent)) {
|
||||
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 Type asmType = expressionType(expression);
|
||||
@@ -333,23 +336,41 @@ public class ExpressionCodegen extends JetVisitor {
|
||||
return;
|
||||
}
|
||||
}
|
||||
PsiElement declarationPsiElement = bindingContext.getDeclarationPsiElement(funDescriptor);
|
||||
if (declarationPsiElement instanceof PsiMethod) {
|
||||
PsiMethod method = (PsiMethod) declarationPsiElement;
|
||||
pushMethodArguments(expression, method);
|
||||
|
||||
final boolean isStatic = method.hasModifierProperty(PsiModifier.STATIC);
|
||||
v.visitMethodInsn(isStatic ? Opcodes.INVOKESTATIC : Opcodes.INVOKEVIRTUAL,
|
||||
JetTypeMapper.jvmName(method.getContainingClass()),
|
||||
method.getName(),
|
||||
getMethodDescriptor(method));
|
||||
final Type type = psiTypeToAsm(method.getReturnType());
|
||||
if (type != Type.VOID_TYPE) {
|
||||
myStack.push(StackValue.onStack(type));
|
||||
if (expression.getParent() instanceof JetDotQualifiedExpression) {
|
||||
final JetDotQualifiedExpression parent = (JetDotQualifiedExpression) expression.getParent();
|
||||
if (!resolvesToClassOrPackage(parent.getReceiverExpression())) {
|
||||
// we have a receiver on stack
|
||||
myStack.pop().put(Type.getObjectType("java/lang/Object"), v);
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
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 {
|
||||
@@ -361,24 +382,23 @@ public class ExpressionCodegen extends JetVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
private void pushMethodArguments(JetCall expression, PsiMethod method) {
|
||||
PsiParameter[] parameters = method.getParameterList().getParameters();
|
||||
|
||||
private void pushMethodArguments(JetCall expression, Method method) {
|
||||
final Type[] argTypes = method.getArgumentTypes();
|
||||
List<JetArgument> args = expression.getValueArguments();
|
||||
for (int i = 0, argsSize = args.size(); i < argsSize; 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());
|
||||
PsiParameter[] parameters = method.getParameterList().getParameters();
|
||||
Type[] parameterTypes = new Type[parameters.length];
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
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) {
|
||||
@@ -798,8 +818,9 @@ public class ExpressionCodegen extends JetVisitor {
|
||||
Type type = JetTypeMapper.psiClassType(javaClass);
|
||||
v.anew(type);
|
||||
v.dup();
|
||||
pushMethodArguments(expression, constructor);
|
||||
v.invokespecial(JetTypeMapper.jvmName(javaClass), "<init>", getMethodDescriptor(constructor));
|
||||
final Method constructorDescriptor = getMethodDescriptor(constructor);
|
||||
pushMethodArguments(expression, constructorDescriptor);
|
||||
v.invokespecial(JetTypeMapper.jvmName(javaClass), "<init>", constructorDescriptor.getDescriptor());
|
||||
myStack.push(StackValue.onStack(type));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -36,22 +36,7 @@ public class FunctionCodegen {
|
||||
}
|
||||
|
||||
private void gen(JetFunction f) {
|
||||
final List<JetParameter> parameters = f.getValueParameters();
|
||||
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);
|
||||
Method method = typeMapper.mapSignature(f);
|
||||
final MethodVisitor mv = v.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
|
||||
method.getName(), method.getDescriptor(), null, null);
|
||||
mv.visitCode();
|
||||
@@ -60,12 +45,13 @@ public class FunctionCodegen {
|
||||
|
||||
List<ValueParameterDescriptor> parameDescrs = bindingContext.getFunctionDescriptor(f).getUnsubstitutedValueParameters();
|
||||
|
||||
Type[] argTypes = method.getArgumentTypes();
|
||||
for (int i = 0; i < parameDescrs.size(); 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);
|
||||
generateReturn(mv, bodyExpression, codegen);
|
||||
mv.visitMaxs(0, 0);
|
||||
|
||||
@@ -2,9 +2,15 @@ package org.jetbrains.jet.codegen;
|
||||
|
||||
import com.intellij.psi.PsiClass;
|
||||
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.types.*;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.commons.Method;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
@@ -105,4 +111,23 @@ public class JetTypeMapper {
|
||||
|
||||
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) {
|
||||
if (fqName.length() == 0) {
|
||||
return "namespace";
|
||||
}
|
||||
return fqName.replace('.', '/') + "/namespace";
|
||||
}
|
||||
|
||||
|
||||
@@ -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"));
|
||||
}
|
||||
|
||||
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 {
|
||||
loadText(text);
|
||||
System.out.println(generateToText());
|
||||
|
||||
Reference in New Issue
Block a user