提交 66089811 编写于 作者: D Dmitry Jemerov

resolve parameters, infer function return type from body expression

上级 d2a2a4c8
...@@ -2,6 +2,9 @@ package org.jetbrains.jet.codegen; ...@@ -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 { ...@@ -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 { ...@@ -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:
} }
......
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; ...@@ -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 { ...@@ -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,26 +85,30 @@ public class FunctionCodegen { ...@@ -58,26 +85,30 @@ 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)) { throw new UnsupportedOperationException("Unknown type " + typeRef);
return Type.getType(String.class); }
}
if ("Int".equals(referencedName)) { private Type mapType(final String name, final List<JetTypeProjection> typeArguments) {
return Type.getType(Integer.class); 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());
} }
throw new UnsupportedOperationException("Unknown type " + typeRef); 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; ...@@ -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 { ...@@ -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; ...@@ -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();
......
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 ...@@ -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;
......
...@@ -60,7 +60,7 @@ public class ExpressionGenTest extends LightDaemonAnalyzerTestCase { ...@@ -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 { ...@@ -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();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册