casts for constants
This commit is contained in:
@@ -2,6 +2,7 @@ package org.jetbrains.jet.codegen;
|
||||
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.types.*;
|
||||
@@ -186,7 +187,7 @@ public class ExpressionCodegen extends JetVisitor {
|
||||
|
||||
@Override
|
||||
public void visitConstantExpression(JetConstantExpression expression) {
|
||||
myStack.push(StackValue.constant(expression.getValue()));
|
||||
myStack.push(StackValue.constant(expression.getValue(), expressionType(expression)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -259,6 +260,18 @@ public class ExpressionCodegen extends JetVisitor {
|
||||
@Override
|
||||
public void visitSimpleNameExpression(JetSimpleNameExpression expression) {
|
||||
final DeclarationDescriptor descriptor = bindingContext.resolveReferenceExpression(expression);
|
||||
if (descriptor instanceof PropertyDescriptor) {
|
||||
final DeclarationDescriptor container = descriptor.getContainingDeclaration();
|
||||
if (isClass(container, "Number")) {
|
||||
Type castType = getCastType(expression.getReferencedName());
|
||||
if (castType != null) {
|
||||
final StackValue value = myStack.pop();
|
||||
value.put(castType, v);
|
||||
myStack.push(StackValue.onStack(castType));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
PsiElement declaration = bindingContext.getDeclarationPsiElement(descriptor);
|
||||
if (declaration instanceof PsiField) {
|
||||
PsiField psiField = (PsiField) declaration;
|
||||
@@ -284,6 +297,32 @@ public class ExpressionCodegen extends JetVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Type getCastType(String castMethodName) {
|
||||
if ("dbl".equals(castMethodName)) {
|
||||
return Type.DOUBLE_TYPE;
|
||||
}
|
||||
if ("flt".equals(castMethodName)) {
|
||||
return Type.FLOAT_TYPE;
|
||||
}
|
||||
if ("lng".equals(castMethodName)) {
|
||||
return Type.LONG_TYPE;
|
||||
}
|
||||
if ("int".equals(castMethodName)) {
|
||||
return Type.INT_TYPE;
|
||||
}
|
||||
if ("chr".equals(castMethodName)) {
|
||||
return Type.CHAR_TYPE;
|
||||
}
|
||||
if ("sht".equals(castMethodName)) {
|
||||
return Type.SHORT_TYPE;
|
||||
}
|
||||
if ("byt".equals(castMethodName)) {
|
||||
return Type.BYTE_TYPE;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitCallExpression(JetCallExpression expression) {
|
||||
JetExpression callee = expression.getCalleeExpression();
|
||||
@@ -354,6 +393,10 @@ public class ExpressionCodegen extends JetVisitor {
|
||||
return Type.getMethodDescriptor(returnType, parameterTypes);
|
||||
}
|
||||
|
||||
private Type expressionType(JetExpression expr) {
|
||||
return typeMapper.mapType(bindingContext.getExpressionType(expr));
|
||||
}
|
||||
|
||||
private static Type psiTypeToAsm(PsiType type) {
|
||||
if (type instanceof PsiPrimitiveType) {
|
||||
if (type == PsiType.VOID) {
|
||||
@@ -444,45 +487,51 @@ public class ExpressionCodegen extends JetVisitor {
|
||||
JetType returnType = bindingContext.getExpressionType(expression);
|
||||
final Type asmType = typeMapper.mapType(returnType);
|
||||
DeclarationDescriptor cls = op.getContainingDeclaration();
|
||||
if (cls instanceof ClassDescriptor) {
|
||||
final String className = cls.getName();
|
||||
if (isNumberPrimitive(className)) {
|
||||
if (op.getName().equals("compareTo")) {
|
||||
generateCompareOp(expression, opToken, asmType);
|
||||
}
|
||||
else {
|
||||
int opcode = opcodeForMethod(op.getName());
|
||||
generateBinaryOp(expression, (FunctionDescriptor) op, opcode);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (className.equals("Hashable")) {
|
||||
if (op.getName().equals("equals")) {
|
||||
final Type leftType = typeMapper.mapType(bindingContext.getExpressionType(expression.getLeft()));
|
||||
final Type rightType = typeMapper.mapType(bindingContext.getExpressionType(expression.getRight()));
|
||||
if (isNumberPrimitive(leftType) && leftType == rightType) {
|
||||
generateCompareOp(expression, opToken, leftType);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedOperationException("Don't know how to generate equality for these types");
|
||||
}
|
||||
}
|
||||
if (isNumberPrimitive(cls)) {
|
||||
if (op.getName().equals("compareTo")) {
|
||||
generateCompareOp(expression, opToken, asmType);
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedOperationException("Don't know how to generate binary op for class " + className);
|
||||
int opcode = opcodeForMethod(op.getName());
|
||||
generateBinaryOp(expression, (FunctionDescriptor) op, opcode);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (isClass(cls, "Hashable")) {
|
||||
if (op.getName().equals("equals")) {
|
||||
final Type leftType = typeMapper.mapType(bindingContext.getExpressionType(expression.getLeft()));
|
||||
final Type rightType = typeMapper.mapType(bindingContext.getExpressionType(expression.getRight()));
|
||||
if (isNumberPrimitive(leftType) && leftType == rightType) {
|
||||
generateCompareOp(expression, opToken, leftType);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedOperationException("Don't know how to generate equality for these types");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new UnsupportedOperationException("Don't know how to generate binary op " + expression);
|
||||
}
|
||||
|
||||
private static boolean isNumberPrimitive(String className) {
|
||||
private static boolean isNumberPrimitive(DeclarationDescriptor descriptor) {
|
||||
if (!(descriptor instanceof ClassDescriptor)) {
|
||||
return false;
|
||||
}
|
||||
String className = descriptor.getName();
|
||||
return className.equals("Int") || className.equals("Long") || className.equals("Short") ||
|
||||
className.equals("Byte") || className.equals("Char") || className.equals("Float") ||
|
||||
className.equals("Double");
|
||||
}
|
||||
|
||||
private static boolean isClass(DeclarationDescriptor descriptor, String name) {
|
||||
if (!(descriptor instanceof ClassDescriptor)) {
|
||||
return false;
|
||||
}
|
||||
String className = descriptor.getName();
|
||||
return className.equals(name);
|
||||
}
|
||||
|
||||
private static boolean isNumberPrimitive(Type type) {
|
||||
return type == Type.INT_TYPE || type == Type.SHORT_TYPE || type == Type.BYTE_TYPE || type == Type.CHAR_TYPE ||
|
||||
type == Type.FLOAT_TYPE || type == Type.DOUBLE_TYPE || type == Type.LONG_TYPE;
|
||||
|
||||
@@ -11,6 +11,12 @@ import org.objectweb.asm.commons.InstructionAdapter;
|
||||
* @author yole
|
||||
*/
|
||||
public abstract class StackValue {
|
||||
protected final Type type;
|
||||
|
||||
public StackValue(Type type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public abstract void put(Type type, InstructionAdapter v);
|
||||
|
||||
public static StackValue local(int index, Type type) {
|
||||
@@ -22,8 +28,8 @@ public abstract class StackValue {
|
||||
return new OnStack(type);
|
||||
}
|
||||
|
||||
public static StackValue constant(Object value) {
|
||||
return new Constant(value);
|
||||
public static StackValue constant(Object value, Type type) {
|
||||
return new Constant(value, type);
|
||||
}
|
||||
|
||||
public static StackValue cmp(IElementType opToken, Type type) {
|
||||
@@ -32,44 +38,54 @@ public abstract class StackValue {
|
||||
|
||||
public abstract void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v);
|
||||
|
||||
private static void box(final Type type, InstructionAdapter v) {
|
||||
if (type == Type.INT_TYPE) {
|
||||
v.invokestatic("java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");
|
||||
}
|
||||
else if (type == Type.BOOLEAN_TYPE) {
|
||||
v.invokestatic("java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;");
|
||||
}
|
||||
else if (type == Type.CHAR_TYPE) {
|
||||
v.invokestatic("java/lang/Character", "valueOf", "(C)Ljava/lang/Character;");
|
||||
}
|
||||
else if (type == Type.SHORT_TYPE) {
|
||||
v.invokestatic("java/lang/Short", "valueOf", "(S)Ljava/lang/Short;");
|
||||
}
|
||||
else if (type == Type.LONG_TYPE) {
|
||||
v.invokestatic("java/lang/Long", "valueOf", "(J)Ljava/lang/Long;");
|
||||
}
|
||||
else if (type == Type.BYTE_TYPE) {
|
||||
v.invokestatic("java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;");
|
||||
}
|
||||
else if (type == Type.FLOAT_TYPE) {
|
||||
v.invokestatic("java/lang/Float", "valueOf", "(F)Ljava/lang/Float;");
|
||||
}
|
||||
else if (type == Type.DOUBLE_TYPE) {
|
||||
v.invokestatic("java/lang/Double", "valueOf", "(D)Ljava/lang/Double;");
|
||||
}
|
||||
}
|
||||
|
||||
protected void coerce(Type type, InstructionAdapter v) {
|
||||
if (type.getSort() == Type.OBJECT) {
|
||||
box(this.type, v);
|
||||
}
|
||||
else if (type != this.type) {
|
||||
v.cast(this.type, type);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Local extends StackValue {
|
||||
private final int index;
|
||||
private final Type type;
|
||||
|
||||
public Local(int index, Type type) {
|
||||
super(type);
|
||||
this.index = index;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(Type type, InstructionAdapter v) {
|
||||
v.load(index, this.type);
|
||||
if (type.getSort() == Type.OBJECT) {
|
||||
if (this.type == Type.INT_TYPE) {
|
||||
v.invokestatic("java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");
|
||||
}
|
||||
else if (this.type == Type.BOOLEAN_TYPE) {
|
||||
v.invokestatic("java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;");
|
||||
}
|
||||
else if (this.type == Type.CHAR_TYPE) {
|
||||
v.invokestatic("java/lang/Character", "valueOf", "(C)Ljava/lang/Character;");
|
||||
}
|
||||
else if (this.type == Type.SHORT_TYPE) {
|
||||
v.invokestatic("java/lang/Short", "valueOf", "(S)Ljava/lang/Short;");
|
||||
}
|
||||
else if (this.type == Type.LONG_TYPE) {
|
||||
v.invokestatic("java/lang/Long", "valueOf", "(J)Ljava/lang/Long;");
|
||||
}
|
||||
else if (this.type == Type.BYTE_TYPE) {
|
||||
v.invokestatic("java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;");
|
||||
}
|
||||
else if (this.type == Type.FLOAT_TYPE) {
|
||||
v.invokestatic("java/lang/Float", "valueOf", "(F)Ljava/lang/Float;");
|
||||
}
|
||||
else if (this.type == Type.DOUBLE_TYPE) {
|
||||
v.invokestatic("java/lang/Double", "valueOf", "(D)Ljava/lang/Double;");
|
||||
}
|
||||
}
|
||||
coerce(type, v);
|
||||
// TODO unbox
|
||||
}
|
||||
|
||||
@@ -86,10 +102,8 @@ public abstract class StackValue {
|
||||
}
|
||||
|
||||
public static class OnStack extends StackValue {
|
||||
private final Type type;
|
||||
|
||||
public OnStack(Type type) {
|
||||
this.type = type;
|
||||
super(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -98,7 +112,7 @@ public abstract class StackValue {
|
||||
|
||||
@Override
|
||||
public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) {
|
||||
if (type == Type.BOOLEAN_TYPE) {
|
||||
if (this.type == Type.BOOLEAN_TYPE) {
|
||||
if (jumpIfFalse) {
|
||||
v.ifeq(label);
|
||||
}
|
||||
@@ -115,39 +129,15 @@ public abstract class StackValue {
|
||||
public static class Constant extends StackValue {
|
||||
private final Object value;
|
||||
|
||||
public Constant(Object value) {
|
||||
public Constant(Object value, Type type) {
|
||||
super(type);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(Type type, InstructionAdapter v) {
|
||||
v.aconst(value);
|
||||
if (type.getSort() == Type.OBJECT) {
|
||||
if (value instanceof Integer) {
|
||||
v.invokestatic("java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");
|
||||
}
|
||||
else if (value instanceof Boolean) {
|
||||
v.invokestatic("java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;");
|
||||
}
|
||||
else if (value instanceof Character) {
|
||||
v.invokestatic("java/lang/Character", "valueOf", "(C)Ljava/lang/Character;");
|
||||
}
|
||||
else if (value instanceof Short) {
|
||||
v.invokestatic("java/lang/Short", "valueOf", "(S)Ljava/lang/Short;");
|
||||
}
|
||||
else if (value instanceof Long) {
|
||||
v.invokestatic("java/lang/Long", "valueOf", "(J)Ljava/lang/Long;");
|
||||
}
|
||||
else if (value instanceof Byte) {
|
||||
v.invokestatic("java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;");
|
||||
}
|
||||
else if (value instanceof Float) {
|
||||
v.invokestatic("java/lang/Float", "valueOf", "(F)Ljava/lang/Float;");
|
||||
}
|
||||
else if (value instanceof Double) {
|
||||
v.invokestatic("java/lang/Double", "valueOf", "(D)Ljava/lang/Double;");
|
||||
}
|
||||
}
|
||||
coerce(type, v);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -166,11 +156,10 @@ public abstract class StackValue {
|
||||
|
||||
private static class NumberCompare extends StackValue {
|
||||
private final IElementType opToken;
|
||||
private final Type type;
|
||||
|
||||
public NumberCompare(IElementType opToken, Type type) {
|
||||
super(type);
|
||||
this.opToken = opToken;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -314,6 +314,19 @@ public class NamespaceGenTest extends LightCodeInsightFixtureTestCase {
|
||||
assertEquals("1.0", main.invoke(null, 1.0));
|
||||
}
|
||||
|
||||
public void testDoubleToInt() throws Exception {
|
||||
loadText("fun foo(a: Double): Int = a.int");
|
||||
System.out.println(generateToText());
|
||||
final Method main = generateFunction();
|
||||
assertEquals(1, main.invoke(null, 1.0));
|
||||
}
|
||||
|
||||
public void testCastConstant() throws Exception {
|
||||
loadText("fun foo(): Double = 1.dbl");
|
||||
final Method main = generateFunction();
|
||||
assertEquals(1.0, 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