package org.simantics.scl.compiler.runtime; import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.simantics.databoard.binding.mutable.Variant; import org.simantics.scl.compiler.types.TApply; import org.simantics.scl.compiler.types.TCon; import org.simantics.scl.compiler.types.Type; import org.simantics.scl.compiler.types.Types; public class ValueConversion { public static Number convertNumber(TCon expectedType, Number value) { if (expectedType == Types.DOUBLE) { if (value instanceof Double) return value; else return new Double(value.doubleValue()); } else if (expectedType == Types.INTEGER) { if (value instanceof Integer) return value; else return new Integer(value.intValue()); } else if (expectedType == Types.FLOAT) { if (value instanceof Float) return value; else return new Float(value.floatValue()); } else if (expectedType == Types.BYTE) { if (value instanceof Byte) return value; else return new Byte(value.byteValue()); } else if (expectedType == Types.SHORT) { if (value instanceof Short) return value; else return new Short(value.shortValue()); } else if (expectedType == Types.LONG) { if (value instanceof Long) return value; else return new Long(value.longValue()); } // Not expecting a number type return value; } public static Object parsePrimitive(TCon expectedType, String value) { if (expectedType == Types.DOUBLE) { return Double.parseDouble(value); } else if (expectedType == Types.INTEGER) { return Integer.parseInt(value); } else if (expectedType == Types.FLOAT) { return Float.parseFloat(value); } else if (expectedType == Types.BYTE) { return Byte.parseByte(value); } else if (expectedType == Types.SHORT) { return Short.parseShort(value); } else if (expectedType == Types.LONG) { return Long.parseLong(value); } else if (expectedType == Types.BOOLEAN) { return Boolean.parseBoolean(value); } else if (expectedType == Types.CHARACTER && value.length() == 1) { return value.charAt(0); } return value; } public static Class getNativeClass(Type expectedType) { if (expectedType == Types.STRING) return String.class; else if (expectedType == Types.DOUBLE) return Double.class; else if (expectedType == Types.INTEGER) return Integer.class; else if (expectedType == Types.FLOAT) return Float.class; else if (expectedType == Types.BYTE) return Byte.class; else if (expectedType == Types.SHORT) return Short.class; else if (expectedType == Types.LONG) return Long.class; else if (expectedType == Types.BOOLEAN) return Boolean.class; else if (expectedType == Types.CHARACTER) return Character.class; else return Object.class; } public static Class getNativePrimitiveClass(Type expectedType) { if (expectedType == Types.STRING) return String.class; else if (expectedType == Types.DOUBLE) return double.class; else if (expectedType == Types.INTEGER) return int.class; else if (expectedType == Types.FLOAT) return float.class; else if (expectedType == Types.BYTE) return byte.class; else if (expectedType == Types.SHORT) return short.class; else if (expectedType == Types.LONG) return long.class; else if (expectedType == Types.BOOLEAN) return boolean.class; else if (expectedType == Types.CHARACTER) return char.class; else return Object.class; } @SuppressWarnings("unchecked") public static boolean needsConversion(Type expectedType, Object value) { if (!needsConversion(expectedType, value.getClass(), false)) return false; if (expectedType instanceof TApply) { TApply apply = (TApply)expectedType; if (apply.function == Types.LIST) { if (!(value instanceof List)) return true; else { for (Object item : (List)value) { if (needsConversion(apply.parameter, item)) return true; } return false; } } } return true; } public static boolean needsConversion(Type expectedType, Class clazz, boolean needPrimitive) { if (expectedType instanceof TCon) { if (needPrimitive && Types.isPrimitive(expectedType)) { Class expectedClass = getNativePrimitiveClass(expectedType); if (expectedClass.isPrimitive()) return clazz == expectedClass; else return expectedClass.isAssignableFrom(clazz); } else if (clazz.isPrimitive()) { return true; } else { return !getNativeClass(expectedType).isAssignableFrom(clazz); } } else if (expectedType instanceof TApply) { TApply apply = (TApply)expectedType; if (apply.function == Types.LIST) { return true; } else if (apply.function == Types.VECTOR || apply.function == Types.MVECTOR || apply.function == Types.ARRAY) { if (!clazz.isArray()) return true; else { boolean needPrimitive2 = apply.function != Types.ARRAY; return needsConversion(apply.parameter, clazz.getComponentType(), needPrimitive2); } } } return false; } @SuppressWarnings({ "rawtypes", "unchecked" }) public static Object fromDynamic(Type expectedType, Object value) { if (value == null) return null; else if (value instanceof Variant) return fromDynamic(expectedType, ((Variant)value).getValue()); else if (expectedType == Types.DYNAMIC) return value; else if (!needsConversion(expectedType, value)) return value; if(expectedType instanceof TCon) { TCon con = (TCon)expectedType; if (con == Types.STRING) return value.toString(); else if (value instanceof Number) return convertNumber(con, (Number)value); else if (value instanceof String && Types.isPrimitive(con)) return parsePrimitive(con, (String)value); } else if(expectedType instanceof TApply) { TApply apply = (TApply)expectedType; Type expectedComponentType = apply.parameter; if(apply.function == Types.LIST) { Class valueClass = value.getClass(); if(valueClass.isArray()) { Class componentType = valueClass.getComponentType(); if(needsConversion(expectedComponentType, componentType, false)) { int length = Array.getLength(value); ArrayList list = new ArrayList(length); for(int i=0;i valueClass = value.getClass(); Class expectedComponentClass = apply.function != Types.ARRAY ? getNativePrimitiveClass(expectedComponentType) : getNativeClass(expectedComponentType); if(valueClass.isArray()) { Class componentType = valueClass.getComponentType(); int length = Array.getLength(value); Object array = Array.newInstance(expectedComponentClass, length); if (needsConversion(expectedComponentType, componentType, apply.function != Types.ARRAY)) { for(int i=0;i list = new ArrayList(); for (Object item : (Iterable)value) { list.add(fromDynamic(expectedComponentType, item)); } if (apply.function != Types.ARRAY && expectedComponentClass.isPrimitive()) { int length = list.size(); Object array = Array.newInstance(expectedComponentClass, length); for (int i = 0; i < length; i++) Array.set(array, i, list.get(i)); return array; } else return list.toArray(); } } } return value; } }