/** * Returns <code>true</code> if type src can be converted to type dst. * * @param src a type * @param dst the type src should be converted to * @return <code>true</code> if type src can be converted to type dst */ public static boolean isConvertibleTo(Type src, Type dst) { if (src == null || dst == null) { return false; } if (src.isFloat() && dst.isFloat()) { return dst.getSizeInBits() >= src.getSizeInBits(); } if (src.isBool() && dst.isBool() || src.isString() && dst.isString() || (src.isInt() || src.isUint()) && (dst.isInt() || dst.isUint()) || (src.isInt() || src.isUint()) && dst.isFloat()) { return true; } if (src.isList() && dst.isList()) { TypeList typeSrc = (TypeList) src; TypeList typeDst = (TypeList) dst; // Recursively check type convertibility if (isConvertibleTo(typeSrc.getType(), typeDst.getType())) { if (typeSrc.getSizeExpr() != null && typeDst.getSizeExpr() != null) { return typeSrc.getSize() <= typeDst.getSize(); } return true; } } return false; }
/** * Returns the Least Upper Bound of the given types, which is the smallest type that can contain * both types. If no such type exists (e.g. when types are not compatible with each other), <code> * null</code> is returned. * * @param t1 a type * @param t2 another type * @return the Least Upper Bound of the given types */ public static Type getLub(Type t1, Type t2) { if (t1 == null || t2 == null) { return null; } if (t1.isBool() && t2.isBool()) { return IrFactory.eINSTANCE.createTypeBool(); } else if (t1.isFloat() && t2.isFloat()) { return IrFactory.eINSTANCE.createTypeFloat( Math.max(((TypeFloat) t1).getSize(), ((TypeFloat) t2).getSize())); } else if (t1.isString() && t2.isString()) { return IrFactory.eINSTANCE.createTypeString(); } else if (t1.isInt() && t2.isInt()) { return IrFactory.eINSTANCE.createTypeInt( Math.max(((TypeInt) t1).getSize(), ((TypeInt) t2).getSize())); } else if (t1.isList() && t2.isList()) { TypeList listType1 = (TypeList) t1; TypeList listType2 = (TypeList) t2; Type type = getLub(listType1.getType(), listType2.getType()); if (type != null) { // only return a list when the underlying type is valid int size = Math.max(listType1.getSize(), listType2.getSize()); return IrFactory.eINSTANCE.createTypeList(size, type); } } else if (t1.isUint() && t2.isUint()) { return IrFactory.eINSTANCE.createTypeUint( Math.max(((TypeUint) t1).getSize(), ((TypeUint) t2).getSize())); } else if (t1.isInt() && t2.isUint()) { int si = ((TypeInt) t1).getSize(); int su = ((TypeUint) t2).getSize(); if (si > su) { return IrFactory.eINSTANCE.createTypeInt(si); } else { return IrFactory.eINSTANCE.createTypeInt(su + 1); } } else if (t1.isUint() && t2.isInt()) { int su = ((TypeUint) t1).getSize(); int si = ((TypeInt) t2).getSize(); if (si > su) { return IrFactory.eINSTANCE.createTypeInt(si); } else { return IrFactory.eINSTANCE.createTypeInt(su + 1); } } return null; }
/** * Returns the type of a binary expression whose left operand has type t1 and right operand has * type t2, and whose operator is given. * * <p>TODO replace automatic int/uint to float casting with explicit casts * * @param op operator * @param t1 type of the first operand * @param t2 type of the second operand * @param source source object * @param feature feature * @return the type of the binary expression, or <code>null</code> */ public static Type getTypeBinary(OpBinary op, Type t1, Type t2) { if (t1 == null || t2 == null) { return null; } switch (op) { case BITAND: return createType(t1, t2, Glb.instance); case BITOR: case BITXOR: return createType(t1, t2, Lub.instance); case TIMES: if ((t1.isInt() || t1.isUint()) && t2.isFloat()) { return IrFactory.eINSTANCE.createTypeFloat(t2.getSizeInBits()); } else if ((t2.isInt() || t2.isUint()) && t1.isFloat()) { return IrFactory.eINSTANCE.createTypeFloat(t1.getSizeInBits()); } else if (t1.isFloat() && t2.isFloat()) { return createType(t1, t2, Lub.instance); } return createType(t1, t2, LubSum.instance); case MINUS: if ((t1.isInt() || t1.isUint()) && t2.isFloat()) { return IrFactory.eINSTANCE.createTypeFloat(t2.getSizeInBits()); } else if ((t2.isInt() || t2.isUint()) && t1.isFloat()) { return IrFactory.eINSTANCE.createTypeFloat(t1.getSizeInBits()); } else if (t1.isFloat() && t2.isFloat()) { return createType(t1, t2, Lub.instance); } return createType(t1, t2, SignedLub.instance); case PLUS: if (t1.isString() && !t2.isList() || t2.isString() && !t1.isList()) { return IrFactory.eINSTANCE.createTypeString(); } if ((t1.isInt() || t1.isUint()) && t2.isFloat()) { return IrFactory.eINSTANCE.createTypeFloat(t2.getSizeInBits()); } else if ((t2.isInt() || t2.isUint()) && t1.isFloat()) { return IrFactory.eINSTANCE.createTypeFloat(t1.getSizeInBits()); } else if (t1.isFloat() && t2.isFloat()) { return createType(t1, t2, Lub.instance); } return createType(t1, t2, LubPlus1.instance); case DIV: case DIV_INT: if ((t1.isInt() || t1.isUint()) && t2.isFloat()) { return IrFactory.eINSTANCE.createTypeFloat(t2.getSizeInBits()); } else if ((t2.isInt() || t2.isUint()) && t1.isFloat()) { return IrFactory.eINSTANCE.createTypeFloat(t1.getSizeInBits()); } else if (t1.isFloat() && t2.isFloat()) { return createType(t1, t2, Lub.instance); } case SHIFT_RIGHT: return EcoreUtil.copy(t1); case MOD: return EcoreUtil.copy(t2); case SHIFT_LEFT: return createType(t1, t2, LubSumPow.instance); case EQ: case GE: case GT: case LE: case LT: case NE: return IrFactory.eINSTANCE.createTypeBool(); case EXP: return null; case LOGIC_AND: case LOGIC_OR: return IrFactory.eINSTANCE.createTypeBool(); default: return null; } }