--- /dev/null
+package org.simantics.scl.compiler.internal.elaboration.constraints;
+
+import gnu.trove.map.hash.THashMap;
+
+import org.cojen.classfile.TypeDesc;
+import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
+import org.simantics.scl.compiler.constants.ClassConstant;
+import org.simantics.scl.compiler.constants.JavaConstructor;
+import org.simantics.scl.compiler.constants.JavaStaticField;
+import org.simantics.scl.compiler.constants.JavaStaticMethod;
+import org.simantics.scl.compiler.constants.StringConstant;
+import org.simantics.scl.compiler.elaboration.expressions.EApply;
+import org.simantics.scl.compiler.elaboration.expressions.EConstant;
+import org.simantics.scl.compiler.elaboration.expressions.ELiteral;
+import org.simantics.scl.compiler.elaboration.java.Builtins;
+import org.simantics.scl.compiler.elaboration.modules.TypeClass;
+import org.simantics.scl.compiler.elaboration.modules.TypeClassInstance;
+import org.simantics.scl.compiler.environment.Environment;
+import org.simantics.scl.compiler.errors.Locations;
+import org.simantics.scl.compiler.types.TApply;
+import org.simantics.scl.compiler.types.TCon;
+import org.simantics.scl.compiler.types.TFun;
+import org.simantics.scl.compiler.types.TPred;
+import org.simantics.scl.compiler.types.TUnion;
+import org.simantics.scl.compiler.types.TVar;
+import org.simantics.scl.compiler.types.Type;
+import org.simantics.scl.compiler.types.Types;
+
+public class ConstraintEnvironment {
+ Environment environment;
+
+ public ConstraintEnvironment(Environment environment) {
+ this.environment = environment;
+ }
+
+ public Superconstraint[] getSuperconstraints(TPred constraint) {
+ TypeClass tc = environment.getTypeClass(constraint.typeClass);
+ if(tc == null) {
+ throw new InternalCompilerError("Didn't find constraint " + constraint + ". Maybe Prelude is not loaded?");
+ }
+ if(tc.context.length == 0)
+ return Superconstraint.EMPTY_ARRAY;
+ Superconstraint[] result = new Superconstraint[tc.context.length];
+ for(int i=0;i<result.length;++i) {
+ result[i] = new Superconstraint(
+ (TPred)tc.context[i].replace(tc.parameters, constraint.parameters),
+ tc.superGenerators[i]
+ );
+ }
+ return result;
+ }
+
+ private static final Type SERIALIZABLE_BOOLEAN = Types.pred(Types.SERIALIZABLE, Types.BOOLEAN);
+ private static final Type SERIALIZABLE_BYTE = Types.pred(Types.SERIALIZABLE, Types.BYTE);
+ private static final Type SERIALIZABLE_SHORT = Types.pred(Types.SERIALIZABLE, Types.SHORT);
+ private static final Type SERIALIZABLE_INTEGER = Types.pred(Types.SERIALIZABLE, Types.INTEGER);
+ private static final Type SERIALIZABLE_LONG = Types.pred(Types.SERIALIZABLE, Types.LONG);
+ private static final Type SERIALIZABLE_FLOAT = Types.pred(Types.SERIALIZABLE, Types.FLOAT);
+ private static final Type SERIALIZABLE_DOUBLE = Types.pred(Types.SERIALIZABLE, Types.DOUBLE);
+ private static final Type SERIALIZABLE_STRING = Types.pred(Types.SERIALIZABLE, Types.STRING);
+
+ private static final Type SERIALIZABLE_BOOLEAN_ARRAY = Types.pred(Types.SERIALIZABLE, Types.BOOLEAN_ARRAY);
+ private static final Type SERIALIZABLE_BYTE_ARRAY = Types.pred(Types.SERIALIZABLE, Types.BYTE_ARRAY);
+ private static final Type SERIALIZABLE_SHORT_ARRAY = Types.pred(Types.SERIALIZABLE, Types.SHORT_ARRAY);
+ private static final Type SERIALIZABLE_INTEGER_ARRAY = Types.pred(Types.SERIALIZABLE, Types.INTEGER_ARRAY);
+ private static final Type SERIALIZABLE_LONG_ARRAY = Types.pred(Types.SERIALIZABLE, Types.LONG_ARRAY);
+ private static final Type SERIALIZABLE_FLOAT_ARRAY = Types.pred(Types.SERIALIZABLE, Types.FLOAT_ARRAY);
+ private static final Type SERIALIZABLE_DOUBLE_ARRAY = Types.pred(Types.SERIALIZABLE, Types.DOUBLE_ARRAY);
+
+ private static final Type SERIALIZABLE_BOOLEAN_VECTOR = Types.pred(Types.SERIALIZABLE, Types.pred(Types.VECTOR, Types.BOOLEAN));
+ private static final Type SERIALIZABLE_BYTE_VECTOR = Types.pred(Types.SERIALIZABLE, Types.pred(Types.VECTOR, Types.BYTE));
+ private static final Type SERIALIZABLE_SHORT_VECTOR = Types.pred(Types.SERIALIZABLE, Types.pred(Types.VECTOR, Types.SHORT));
+ private static final Type SERIALIZABLE_INTEGER_VECTOR = Types.pred(Types.SERIALIZABLE, Types.pred(Types.VECTOR, Types.INTEGER));
+ private static final Type SERIALIZABLE_LONG_VECTOR = Types.pred(Types.SERIALIZABLE, Types.pred(Types.VECTOR, Types.LONG));
+ private static final Type SERIALIZABLE_FLOAT_VECTOR = Types.pred(Types.SERIALIZABLE, Types.pred(Types.VECTOR, Types.FLOAT));
+ private static final Type SERIALIZABLE_DOUBLE_VECTOR = Types.pred(Types.SERIALIZABLE, Types.pred(Types.VECTOR, Types.DOUBLE));
+
+ private static final Type SERIALIZABLE_TUPLE0 = Types.pred(Types.SERIALIZABLE, Types.tuple());
+ private static final Type SERIALIZABLE_VARIANT = Types.pred(Types.SERIALIZABLE, Types.VARIANT);
+
+ public Reduction reduce(TPred constraint) {
+ // VecComp
+ if(constraint.typeClass == Types.VEC_COMP) {
+ Type parameter = Types.canonical(constraint.parameters[0]);
+ if(parameter.isGround())
+ return new Reduction(new ELiteral(new ClassConstant(Types.pred(Types.VEC_COMP, parameter), parameter)),
+ Type.EMPTY_ARRAY, TPred.EMPTY_ARRAY);
+ }
+ // Serializable
+ if(constraint.typeClass == Types.SERIALIZABLE) {
+ Type parameter = Types.canonical(constraint.parameters[0]);
+ if(parameter instanceof TCon) {
+ TCon con = (TCon)parameter;
+ if(con == Types.DOUBLE)
+ return new Reduction(
+ new ELiteral(new JavaStaticField("org/simantics/databoard/Bindings", "DOUBLE", Types.NO_EFFECTS, TypeDesc.forClass("org/simantics/databoard/binding/DoubleBinding"), SERIALIZABLE_DOUBLE, -1)),
+ Type.EMPTY_ARRAY, TPred.EMPTY_ARRAY);
+ else if(con == Types.STRING)
+ return new Reduction(
+ new ELiteral(new JavaStaticField("org/simantics/databoard/Bindings", "STRING", Types.NO_EFFECTS, TypeDesc.forClass("org/simantics/databoard/binding/StringBinding"), SERIALIZABLE_STRING, -1)),
+ Type.EMPTY_ARRAY, TPred.EMPTY_ARRAY);
+ else if(con == Types.INTEGER)
+ return new Reduction(
+ new ELiteral(new JavaStaticField("org/simantics/databoard/Bindings", "INTEGER", Types.NO_EFFECTS, TypeDesc.forClass("org/simantics/databoard/binding/IntegerBinding"), SERIALIZABLE_INTEGER, -1)),
+ Type.EMPTY_ARRAY, TPred.EMPTY_ARRAY);
+ else if(con == Types.BOOLEAN)
+ return new Reduction(
+ new ELiteral(new JavaStaticField("org/simantics/databoard/Bindings", "BOOLEAN", Types.NO_EFFECTS, TypeDesc.forClass("org/simantics/databoard/binding/BooleanBinding"), SERIALIZABLE_BOOLEAN, -1)),
+ Type.EMPTY_ARRAY, TPred.EMPTY_ARRAY);
+ else if(con == Types.BYTE)
+ return new Reduction(
+ new ELiteral(new JavaStaticField("org/simantics/databoard/Bindings", "BYTE", Types.NO_EFFECTS, TypeDesc.forClass("org/simantics/databoard/binding/ByteBinding"), SERIALIZABLE_BYTE, -1)),
+ Type.EMPTY_ARRAY, TPred.EMPTY_ARRAY);
+ else if(con == Types.FLOAT)
+ return new Reduction(
+ new ELiteral(new JavaStaticField("org/simantics/databoard/Bindings", "FLOAT", Types.NO_EFFECTS, TypeDesc.forClass("org/simantics/databoard/binding/FloatBinding"), SERIALIZABLE_FLOAT, -1)),
+ Type.EMPTY_ARRAY, TPred.EMPTY_ARRAY);
+ else if(con == Types.LONG)
+ return new Reduction(
+ new ELiteral(new JavaStaticField("org/simantics/databoard/Bindings", "LONG", Types.NO_EFFECTS, TypeDesc.forClass("org/simantics/databoard/binding/LongBinding"), SERIALIZABLE_LONG, -1)),
+ Type.EMPTY_ARRAY, TPred.EMPTY_ARRAY);
+ else if(con == Types.tupleConstructor(0))
+ return new Reduction(
+ new ELiteral(new JavaStaticField("org/simantics/databoard/Bindings", "VOID", Types.NO_EFFECTS, TypeDesc.forClass("org/simantics/databoard/binding/Binding"), SERIALIZABLE_TUPLE0, -1)),
+ Type.EMPTY_ARRAY, TPred.EMPTY_ARRAY);
+ else if(con == Types.VARIANT)
+ return new Reduction(
+ new ELiteral(new JavaStaticField("org/simantics/databoard/Bindings", "VARIANT", Types.NO_EFFECTS, TypeDesc.forClass("org/simantics/databoard/binding/VariantBinding"), SERIALIZABLE_VARIANT, -1)),
+ Type.EMPTY_ARRAY, TPred.EMPTY_ARRAY);
+ else if(con == Types.DOUBLE_ARRAY)
+ return new Reduction(
+ new ELiteral(new JavaStaticField("org/simantics/databoard/Bindings", "DOUBLE_ARRAY", Types.NO_EFFECTS, TypeDesc.forClass("org/simantics/databoard/binding/ArrayBinding"), SERIALIZABLE_DOUBLE_ARRAY, -1)),
+ Type.EMPTY_ARRAY, TPred.EMPTY_ARRAY);
+ else if(con == Types.INTEGER_ARRAY)
+ return new Reduction(
+ new ELiteral(new JavaStaticField("org/simantics/databoard/Bindings", "INTEGER_ARRAY", Types.NO_EFFECTS, TypeDesc.forClass("org/simantics/databoard/binding/ArrayBinding"), SERIALIZABLE_INTEGER_ARRAY, -1)),
+ Type.EMPTY_ARRAY, TPred.EMPTY_ARRAY);
+ else if(con == Types.BOOLEAN_ARRAY)
+ return new Reduction(
+ new ELiteral(new JavaStaticField("org/simantics/databoard/Bindings", "BOOLEAN_ARRAY", Types.NO_EFFECTS, TypeDesc.forClass("org/simantics/databoard/binding/ArrayBinding"), SERIALIZABLE_BOOLEAN_ARRAY, -1)),
+ Type.EMPTY_ARRAY, TPred.EMPTY_ARRAY);
+ else if(con == Types.BYTE_ARRAY)
+ return new Reduction(
+ new ELiteral(new JavaStaticField("org/simantics/databoard/Bindings", "BYTE_ARRAY", Types.NO_EFFECTS, TypeDesc.forClass("org/simantics/databoard/binding/ArrayBinding"), SERIALIZABLE_BYTE_ARRAY, -1)),
+ Type.EMPTY_ARRAY, TPred.EMPTY_ARRAY);
+ else if(con == Types.FLOAT_ARRAY)
+ return new Reduction(
+ new ELiteral(new JavaStaticField("org/simantics/databoard/Bindings", "FLOAT_ARRAY", Types.NO_EFFECTS, TypeDesc.forClass("org/simantics/databoard/binding/ArrayBinding"), SERIALIZABLE_FLOAT_ARRAY, -1)),
+ Type.EMPTY_ARRAY, TPred.EMPTY_ARRAY);
+ else if(con == Types.LONG_ARRAY)
+ return new Reduction(
+ new ELiteral(new JavaStaticField("org/simantics/databoard/Bindings", "LONG_ARRAY", Types.NO_EFFECTS, TypeDesc.forClass("org/simantics/databoard/binding/ArrayBinding"), SERIALIZABLE_LONG_ARRAY, -1)),
+ Type.EMPTY_ARRAY, TPred.EMPTY_ARRAY);
+ }
+ else if(parameter instanceof TApply) {
+ TApply apply1 = (TApply)parameter;
+ Type f1 = Types.canonical(apply1.function);
+ Type p1 = Types.canonical(apply1.parameter);
+ if(f1 instanceof TCon) {
+ TCon con = (TCon)f1;
+ if(con == Types.LIST)
+ return new Reduction(
+ new ELiteral(new JavaConstructor("org/simantics/databoard/binding/impl/ArrayListBinding", Types.NO_EFFECTS,
+ Types.pred(Types.SERIALIZABLE, Types.list(p1)), Types.pred(Types.SERIALIZABLE, p1))),
+ Type.EMPTY_ARRAY, new TPred[] { Types.pred(Types.SERIALIZABLE, p1) });
+ else if(con == Types.MAYBE)
+ return new Reduction(
+ new ELiteral(new JavaConstructor("org/simantics/databoard/binding/impl/OptionalBindingDefault", Types.NO_EFFECTS,
+ Types.pred(Types.SERIALIZABLE, Types.apply(Types.MAYBE, p1)), Types.pred(Types.SERIALIZABLE, p1))),
+ Type.EMPTY_ARRAY, new TPred[] { Types.pred(Types.SERIALIZABLE, p1) });
+ else if(con == Types.VECTOR) {
+ if (p1 == Types.DOUBLE)
+ return new Reduction(
+ new ELiteral(new JavaStaticField("org/simantics/databoard/Bindings", "DOUBLE_ARRAY", Types.NO_EFFECTS, TypeDesc.forClass("org/simantics/databoard/binding/ArrayBinding"), SERIALIZABLE_DOUBLE_VECTOR, -1)),
+ Type.EMPTY_ARRAY, TPred.EMPTY_ARRAY);
+ else if(p1 == Types.INTEGER)
+ return new Reduction(
+ new ELiteral(new JavaStaticField("org/simantics/databoard/Bindings", "INTEGER_ARRAY", Types.NO_EFFECTS, TypeDesc.forClass("org/simantics/databoard/binding/ArrayBinding"), SERIALIZABLE_INTEGER_VECTOR, -1)),
+ Type.EMPTY_ARRAY, TPred.EMPTY_ARRAY);
+ else if(p1 == Types.BOOLEAN)
+ return new Reduction(
+ new ELiteral(new JavaStaticField("org/simantics/databoard/Bindings", "BOOLEAN_ARRAY", Types.NO_EFFECTS, TypeDesc.forClass("org/simantics/databoard/binding/ArrayBinding"), SERIALIZABLE_BOOLEAN_VECTOR, -1)),
+ Type.EMPTY_ARRAY, TPred.EMPTY_ARRAY);
+ else if(p1 == Types.BYTE)
+ return new Reduction(
+ new ELiteral(new JavaStaticField("org/simantics/databoard/Bindings", "BYTE_ARRAY", Types.NO_EFFECTS, TypeDesc.forClass("org/simantics/databoard/binding/ArrayBinding"), SERIALIZABLE_BYTE_VECTOR, -1)),
+ Type.EMPTY_ARRAY, TPred.EMPTY_ARRAY);
+ else if(p1 == Types.FLOAT)
+ return new Reduction(
+ new ELiteral(new JavaStaticField("org/simantics/databoard/Bindings", "FLOAT_ARRAY", Types.NO_EFFECTS, TypeDesc.forClass("org/simantics/databoard/binding/ArrayBinding"), SERIALIZABLE_FLOAT_VECTOR, -1)),
+ Type.EMPTY_ARRAY, TPred.EMPTY_ARRAY);
+ else if(p1 == Types.LONG)
+ return new Reduction(
+ new ELiteral(new JavaStaticField("org/simantics/databoard/Bindings", "LONG_ARRAY", Types.NO_EFFECTS, TypeDesc.forClass("org/simantics/databoard/binding/ArrayBinding"), SERIALIZABLE_LONG_VECTOR, -1)),
+ Type.EMPTY_ARRAY, TPred.EMPTY_ARRAY);
+ else
+ return new Reduction(
+ new ELiteral(new JavaStaticMethod("org/simantics/databoard/Bindings", "getArrayBinding", Types.NO_EFFECTS,
+ Types.pred(Types.SERIALIZABLE, Types.pred(Types.VECTOR, p1)), Types.pred(Types.SERIALIZABLE, p1))),
+ Type.EMPTY_ARRAY, new TPred[] { Types.pred(Types.SERIALIZABLE, p1) });
+ }
+ }
+ else if(f1 instanceof TApply) {
+ TApply apply2 = (TApply)parameter;
+ Type f2 = Types.canonical(apply2.function);
+ Type p2 = Types.canonical(apply2.parameter);
+ if(f2 instanceof TCon) {
+ TCon con = (TCon)f2;
+ /*if(con == Types.tupleConstructor(2)) {
+ return new Reduction(
+ new EConstant(Builtins.TUPLE_CONSTRUCTORS[2]new JavaConstructor("org/simantics/databoard/binding/impl/ArrayListBinding", Types.NO_EFFECTS,
+ Types.pred(Types.SERIALIZABLE, p1), Types.pred(Types.SERIALIZABLE, Types.list(p1)))),
+ Type.EMPTY_ARRAY,
+ new TPred[] { Types.pred(Types.SERIALIZABLE, p2), Types.pred(Types.SERIALIZABLE, p1) });
+ }*/
+ }
+ }
+ }
+
+ // Default to a binding as an ObjectVariantBinding
+ // This can be applied only if the type is ground type (i.e. does not contain type variables),
+ // because otherwise the Serializable instance could be provided as a parameter to the function
+ if(parameter.isGround())
+ return new Reduction(
+ new ELiteral(new JavaStaticField("org/simantics/databoard/Bindings", "OBJECT", Types.NO_EFFECTS,
+ TypeDesc.forClass("org/simantics/databoard/binding/VariantBinding"), Types.pred(Types.SERIALIZABLE, parameter), -1)),
+ Type.EMPTY_ARRAY, TPred.EMPTY_ARRAY);
+ }
+
+ // Typeable
+ else if(constraint.typeClass == Types.TYPEABLE) {
+ Type parameter = Types.canonical(constraint.parameters[0]);
+ if(parameter instanceof TCon) {
+ TCon con = (TCon)parameter;
+ return new Reduction(
+ new EApply(Locations.NO_LOCATION,
+ new EConstant(Builtins.INSTANCE.getValue("TCon")),
+ new ELiteral(new StringConstant(con.module)),
+ new ELiteral(new StringConstant(con.name))),
+ Type.EMPTY_ARRAY, TPred.EMPTY_ARRAY);
+ }
+ else if(parameter instanceof TApply) {
+ TApply apply = (TApply)parameter;
+ return new Reduction(
+ new EConstant(Builtins.INSTANCE.getValue("TApply")),
+ Type.EMPTY_ARRAY, new TPred[] {
+ Types.pred(Types.TYPEABLE, apply.function),
+ Types.pred(Types.TYPEABLE, apply.parameter),
+ });
+ }
+ else if(parameter instanceof TFun) {
+ TFun fun = (TFun)parameter;
+ return new Reduction(
+ new EConstant(Builtins.INSTANCE.getValue("TFun")),
+ Type.EMPTY_ARRAY, new TPred[] {
+ Types.pred(Types.TYPEABLE, fun.domain),
+ Types.pred(Types.TYPEABLE, fun.effect),
+ Types.pred(Types.TYPEABLE, fun.range)
+ });
+ }
+ else if(parameter instanceof TUnion) {
+ TUnion union = (TUnion)parameter;
+
+ /*TPred[] demands = new TPred[union.effects.length];
+ for(int i=0;i<union.effects.length;++i)
+ demands[i] = Types.pred(Types.TYPEABLE, union.effects[i]);*/
+ if(union.effects.length == 0)
+ return new Reduction(
+ new EConstant(Builtins.INSTANCE.getValue("TPure")),
+ Type.EMPTY_ARRAY,
+ TPred.EMPTY_ARRAY);
+ }
+ }
+
+ // Standard case
+ THashMap<TVar, Type> substitution = new THashMap<TVar, Type>();
+ for(TypeClassInstance inst : environment.getInstances(constraint.typeClass)) {
+ if(Types.match(inst.instance, constraint, substitution)) {
+ TPred[] demands = new TPred[inst.context.length];
+ for(int i=0;i<demands.length;++i) {
+ demands[i] = (TPred)inst.context[i].replace(substitution);
+ }
+ Type[] parameters = new Type[inst.generatorParameters.length];
+ for(int i=0;i<parameters.length;++i) {
+ Type parameter = substitution.get(inst.generatorParameters[i]);
+ if(parameter == null)
+ parameter = inst.generatorParameters[i]; // TODO Is this correct?
+ parameters[i] = parameter;
+ }
+ return new Reduction(new ELiteral(inst.generator), parameters, demands);
+ }
+ else
+ substitution.clear();
+ }
+ return null;
+ }
+}