resolve parameters, infer function return type from body expression
This commit is contained in:
@@ -2,6 +2,9 @@ package org.jetbrains.jet.codegen;
|
|||||||
|
|
||||||
import gnu.trove.TObjectIntHashMap;
|
import gnu.trove.TObjectIntHashMap;
|
||||||
import org.jetbrains.jet.lang.psi.*;
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
|
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||||
|
import org.jetbrains.jet.lang.types.DeclarationDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.types.ValueParameterDescriptor;
|
||||||
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;
|
||||||
@@ -21,9 +24,11 @@ public class ExpressionCodegen extends JetVisitor {
|
|||||||
private final InstructionAdapter v;
|
private final InstructionAdapter v;
|
||||||
private final TObjectIntHashMap<JetProperty> myVarIndex = new TObjectIntHashMap<JetProperty>();
|
private final TObjectIntHashMap<JetProperty> myVarIndex = new TObjectIntHashMap<JetProperty>();
|
||||||
private int myMaxVarIndex = 0;
|
private int myMaxVarIndex = 0;
|
||||||
|
private final BindingContext bindingContext;
|
||||||
|
|
||||||
public ExpressionCodegen(MethodVisitor v) {
|
public ExpressionCodegen(MethodVisitor v, BindingContext bindingContext) {
|
||||||
this.v = new InstructionAdapter(v);
|
this.v = new InstructionAdapter(v);
|
||||||
|
this.bindingContext = bindingContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void gen(JetElement expr) {
|
private void gen(JetElement expr) {
|
||||||
@@ -243,6 +248,18 @@ public class ExpressionCodegen extends JetVisitor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitReferenceExpression(JetReferenceExpression expression) {
|
||||||
|
final DeclarationDescriptor descriptor = bindingContext.resolve(expression);
|
||||||
|
if (descriptor instanceof ValueParameterDescriptor) {
|
||||||
|
final int index = ((ValueParameterDescriptor) descriptor).getIndex();
|
||||||
|
v.visitVarInsn(Opcodes.ALOAD, index); // TODO +1 for non-static methods
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new UnsupportedOperationException("don't know how to generate reference " + descriptor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Type getType(JetProperty var) {
|
private Type getType(JetProperty var) {
|
||||||
return InstructionAdapter.OBJECT_TYPE; // TODO:
|
return InstructionAdapter.OBJECT_TYPE; // TODO:
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package org.jetbrains.jet.codegen;
|
package org.jetbrains.jet.codegen;
|
||||||
|
|
||||||
import org.jetbrains.jet.lang.psi.*;
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
|
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||||
|
import org.jetbrains.jet.lang.types.FunctionDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.types.JetStandardClasses;
|
||||||
import org.objectweb.asm.ClassVisitor;
|
import org.objectweb.asm.ClassVisitor;
|
||||||
import org.objectweb.asm.MethodVisitor;
|
import org.objectweb.asm.MethodVisitor;
|
||||||
import org.objectweb.asm.Opcodes;
|
import org.objectweb.asm.Opcodes;
|
||||||
@@ -14,9 +17,11 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public class FunctionCodegen {
|
public class FunctionCodegen {
|
||||||
private final ClassVisitor v;
|
private final ClassVisitor v;
|
||||||
|
private final BindingContext bindingContext;
|
||||||
|
|
||||||
public FunctionCodegen(ClassVisitor v) {
|
public FunctionCodegen(ClassVisitor v, BindingContext bindingContext) {
|
||||||
this.v = v;
|
this.v = v;
|
||||||
|
this.bindingContext = bindingContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void gen(JetFunction f, JetNamespace owner) {
|
public void gen(JetFunction f, JetNamespace owner) {
|
||||||
@@ -26,28 +31,50 @@ public class FunctionCodegen {
|
|||||||
parameterTypes[i] = mapTypeReference(parameters.get(i).getTypeReference());
|
parameterTypes[i] = mapTypeReference(parameters.get(i).getTypeReference());
|
||||||
}
|
}
|
||||||
final JetTypeReference returnTypeRef = f.getReturnTypeRef();
|
final JetTypeReference returnTypeRef = f.getReturnTypeRef();
|
||||||
Type returnType = returnTypeRef == null ? Type.VOID_TYPE : mapTypeReference(returnTypeRef);
|
Type returnType;
|
||||||
|
if (returnTypeRef == null) {
|
||||||
|
final FunctionDescriptor functionDescriptor = bindingContext.getFunctionDescriptor(f);
|
||||||
|
final org.jetbrains.jet.lang.types.Type type = functionDescriptor.getUnsubstitutedReturnType();
|
||||||
|
if (type.equals(JetStandardClasses.getUnitType())) {
|
||||||
|
returnType = Type.VOID_TYPE;
|
||||||
|
}
|
||||||
|
else if (type.equals(JetStandardClasses.getIntType())) {
|
||||||
|
returnType = Type.getType(Integer.class);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new UnsupportedOperationException("don't know how to map type " + type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
returnType = mapTypeReference(returnTypeRef);
|
||||||
|
}
|
||||||
Method method = new Method(f.getName(), returnType, parameterTypes);
|
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();
|
||||||
final JetExpression bodyExpression = f.getBodyExpression();
|
final JetExpression bodyExpression = f.getBodyExpression();
|
||||||
bodyExpression.accept(new ExpressionCodegen(mv));
|
bodyExpression.accept(new ExpressionCodegen(mv, bindingContext));
|
||||||
if (needReturn(bodyExpression)) {
|
generateReturn(mv, bodyExpression);
|
||||||
mv.visitInsn(Opcodes.RETURN);
|
|
||||||
}
|
|
||||||
mv.visitMaxs(0, 0);
|
mv.visitMaxs(0, 0);
|
||||||
mv.visitEnd();
|
mv.visitEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean needReturn(JetExpression bodyExpression) {
|
private void generateReturn(MethodVisitor mv, JetExpression bodyExpression) {
|
||||||
|
if (!endsWithReturn(bodyExpression)) {
|
||||||
|
final org.jetbrains.jet.lang.types.Type expressionType = bindingContext.getExpressionType(bodyExpression);
|
||||||
|
if (expressionType.equals(JetStandardClasses.getUnitType())) {
|
||||||
|
mv.visitInsn(Opcodes.RETURN);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mv.visitInsn(Opcodes.ARETURN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean endsWithReturn(JetExpression bodyExpression) {
|
||||||
if (bodyExpression instanceof JetBlockExpression) {
|
if (bodyExpression instanceof JetBlockExpression) {
|
||||||
final List<JetElement> statements = ((JetBlockExpression) bodyExpression).getStatements();
|
final List<JetElement> statements = ((JetBlockExpression) bodyExpression).getStatements();
|
||||||
if (statements.size() == 0) {
|
return statements.size() > 0 && statements.get(statements.size()-1) instanceof JetReturnExpression;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
final JetElement jetElement = statements.get(statements.size() - 1);
|
|
||||||
return !(jetElement instanceof JetReturnExpression);
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -58,28 +85,32 @@ public class FunctionCodegen {
|
|||||||
}
|
}
|
||||||
final JetTypeElement typeElement = typeRef.getTypeElement();
|
final JetTypeElement typeElement = typeRef.getTypeElement();
|
||||||
if (typeElement instanceof JetUserType) {
|
if (typeElement instanceof JetUserType) {
|
||||||
final String referencedName = ((JetUserType) typeElement).getReferencedName();
|
final JetUserType userType = (JetUserType) typeElement;
|
||||||
if ("Array".equals(referencedName)) {
|
return mapType(userType.getReferencedName(), userType.getTypeArguments());
|
||||||
final List<JetTypeProjection> 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);
|
|
||||||
}
|
|
||||||
if ("Int".equals(referencedName)) {
|
|
||||||
return Type.getType(Integer.class);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new UnsupportedOperationException("Unknown type " + typeRef);
|
throw new UnsupportedOperationException("Unknown type " + typeRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Type mapType(final String name, final List<JetTypeProjection> typeArguments) {
|
||||||
|
if ("Array".equals(name)) {
|
||||||
|
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(name)) {
|
||||||
|
return Type.getType(String.class);
|
||||||
|
}
|
||||||
|
if ("Int".equals(name)) {
|
||||||
|
return Type.getType(Integer.class);
|
||||||
|
}
|
||||||
|
throw new UnsupportedOperationException("Unknown type " + name);
|
||||||
|
}
|
||||||
|
|
||||||
public void gen(JetFunction f, JetClass owner) {
|
public void gen(JetFunction f, JetClass owner) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,14 @@ import org.jetbrains.jet.lang.psi.JetDeclaration;
|
|||||||
import org.jetbrains.jet.lang.psi.JetFunction;
|
import org.jetbrains.jet.lang.psi.JetFunction;
|
||||||
import org.jetbrains.jet.lang.psi.JetNamespace;
|
import org.jetbrains.jet.lang.psi.JetNamespace;
|
||||||
import org.jetbrains.jet.lang.psi.JetProperty;
|
import org.jetbrains.jet.lang.psi.JetProperty;
|
||||||
|
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||||
|
import org.jetbrains.jet.lang.resolve.TopDownAnalyzer;
|
||||||
|
import org.jetbrains.jet.lang.types.JetStandardClasses;
|
||||||
import org.objectweb.asm.ClassVisitor;
|
import org.objectweb.asm.ClassVisitor;
|
||||||
import org.objectweb.asm.Opcodes;
|
import org.objectweb.asm.Opcodes;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author max
|
* @author max
|
||||||
*/
|
*/
|
||||||
@@ -15,8 +20,11 @@ public class NamespaceCodegen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void generate(JetNamespace namespace, ClassVisitor v) {
|
public void generate(JetNamespace namespace, ClassVisitor v) {
|
||||||
|
List<JetDeclaration> declarations = namespace.getDeclarations();
|
||||||
|
BindingContext bindingContext = new TopDownAnalyzer().process(JetStandardClasses.STANDARD_CLASSES, declarations);
|
||||||
|
|
||||||
final PropertyCodegen propertyCodegen = new PropertyCodegen(v);
|
final PropertyCodegen propertyCodegen = new PropertyCodegen(v);
|
||||||
final FunctionCodegen functionCodegen = new FunctionCodegen(v);
|
final FunctionCodegen functionCodegen = new FunctionCodegen(v, bindingContext);
|
||||||
v.visit(Opcodes.V1_6,
|
v.visit(Opcodes.V1_6,
|
||||||
Opcodes.ACC_PUBLIC,
|
Opcodes.ACC_PUBLIC,
|
||||||
getJVMClassName(namespace),
|
getJVMClassName(namespace),
|
||||||
|
|||||||
@@ -4,6 +4,12 @@ package org.jetbrains.jet.lang.types;
|
|||||||
* @author abreslav
|
* @author abreslav
|
||||||
*/
|
*/
|
||||||
public interface ValueParameterDescriptor extends PropertyDescriptor {
|
public interface ValueParameterDescriptor extends PropertyDescriptor {
|
||||||
|
/**
|
||||||
|
* Returns the 0-based index of the value parameter in the parameter list of its containing function.
|
||||||
|
*
|
||||||
|
* @return the parameter index
|
||||||
|
*/
|
||||||
|
int getIndex();
|
||||||
boolean hasDefaultValue();
|
boolean hasDefaultValue();
|
||||||
boolean isRef();
|
boolean isRef();
|
||||||
boolean isVararg();
|
boolean isVararg();
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package org.jetbrains.jet.lang.types;
|
package org.jetbrains.jet.lang.types;
|
||||||
|
|
||||||
|
import com.intellij.psi.PsiElement;
|
||||||
|
import org.jetbrains.jet.lang.psi.JetDeclaration;
|
||||||
import org.jetbrains.jet.lang.psi.JetParameter;
|
import org.jetbrains.jet.lang.psi.JetParameter;
|
||||||
|
import org.jetbrains.jet.lang.psi.JetParameterList;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -17,6 +20,16 @@ public class ValueParameterDescriptorImpl extends PropertyDescriptorImpl impleme
|
|||||||
this.isVararg = isVararg;
|
this.isVararg = isVararg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getIndex() {
|
||||||
|
final JetDeclaration element = getPsiElement();
|
||||||
|
final PsiElement parent = element.getParent();
|
||||||
|
if (parent instanceof JetParameterList) {
|
||||||
|
return ((JetParameterList) parent).getParameters().indexOf(element);
|
||||||
|
}
|
||||||
|
throw new IllegalStateException("couldn't find index for parameter");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasDefaultValue() {
|
public boolean hasDefaultValue() {
|
||||||
return hasDefaultValue;
|
return hasDefaultValue;
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
fun foo(a : Int) = a
|
||||||
@@ -60,7 +60,7 @@ public class ExpressionGenTest extends LightDaemonAnalyzerTestCase {
|
|||||||
JetProperty p = PsiTreeUtil.getParentOfType(getFile().findElementAt(0), JetProperty.class);
|
JetProperty p = PsiTreeUtil.getParentOfType(getFile().findElementAt(0), JetProperty.class);
|
||||||
|
|
||||||
TraceMethodVisitor trace = new TraceMethodVisitor();
|
TraceMethodVisitor trace = new TraceMethodVisitor();
|
||||||
p.getInitializer().accept(new ExpressionCodegen(trace));
|
p.getInitializer().accept(new ExpressionCodegen(trace, null));
|
||||||
|
|
||||||
StringWriter out = new StringWriter();
|
StringWriter out = new StringWriter();
|
||||||
trace.print(new PrintWriter(out));
|
trace.print(new PrintWriter(out));
|
||||||
|
|||||||
@@ -45,6 +45,17 @@ public class NamespaceGenTest extends LightCodeInsightFixtureTestCase {
|
|||||||
assertEquals(new Integer(42), returnValue);
|
assertEquals(new Integer(42), returnValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testReturnA() throws Exception {
|
||||||
|
myFixture.configureByFile(JetParsingTest.getTestDataDir() + "/codegen/returnA.jet");
|
||||||
|
final String text = generateToText();
|
||||||
|
System.out.println(text);
|
||||||
|
|
||||||
|
final Class aClass = generateToClass();
|
||||||
|
final Method main = firstMethod(aClass);
|
||||||
|
final Object returnValue = main.invoke(null, 42);
|
||||||
|
assertEquals(new Integer(42), returnValue);
|
||||||
|
}
|
||||||
|
|
||||||
private String generateToText() {
|
private String generateToText() {
|
||||||
StringWriter writer = new StringWriter();
|
StringWriter writer = new StringWriter();
|
||||||
JetFile jetFile = (JetFile) myFixture.getFile();
|
JetFile jetFile = (JetFile) myFixture.getFile();
|
||||||
|
|||||||
Reference in New Issue
Block a user