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.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";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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());
|
||||||
|
|||||||
Reference in New Issue
Block a user