--- /dev/null
+package org.simantics.scl.compiler.internal.deriving;
+
+import java.util.ArrayList;
+
+import org.simantics.scl.compiler.common.datatypes.Constructor;
+import org.simantics.scl.compiler.constants.IntegerConstant;
+import org.simantics.scl.compiler.elaboration.errors.NotPatternException;
+import org.simantics.scl.compiler.elaboration.expressions.EApply;
+import org.simantics.scl.compiler.elaboration.expressions.ELiteral;
+import org.simantics.scl.compiler.elaboration.expressions.EVar;
+import org.simantics.scl.compiler.elaboration.expressions.Expression;
+import org.simantics.scl.compiler.elaboration.modules.TypeConstructor;
+import org.simantics.scl.compiler.environment.AmbiguousNameException;
+import org.simantics.scl.compiler.environment.Environment;
+import org.simantics.scl.compiler.environment.Environments;
+import org.simantics.scl.compiler.errors.ErrorLog;
+import org.simantics.scl.compiler.internal.parsing.declarations.DDerivingInstanceAst;
+import org.simantics.scl.compiler.internal.parsing.declarations.DInstanceAst;
+import org.simantics.scl.compiler.internal.parsing.declarations.DValueAst;
+import org.simantics.scl.compiler.internal.parsing.expressions.Expressions;
+import org.simantics.scl.compiler.internal.parsing.translation.ProcessedDInstanceAst;
+import org.simantics.scl.compiler.internal.parsing.translation.ValueRepository;
+import org.simantics.scl.compiler.internal.parsing.types.TVarAst;
+import org.simantics.scl.compiler.types.TCon;
+
+class HashableDeriver implements InstanceDeriver {
+
+ @Override
+ public void derive(
+ ErrorLog errorLog,
+ Environment environment,
+ ArrayList<ProcessedDInstanceAst> instancesAst,
+ DDerivingInstanceAst der) {
+ // Analyze
+ if(der.types.length != 1) {
+ errorLog.log(der.location, "Invalid number of parameters to " + der.name);
+ return;
+ }
+ TVarAst headType = DerivingUtils.getHeadType(der.types[0]);
+ if(headType == null) {
+ errorLog.log(der.types[0].location, "Cannot derive Hashable instance for the type " + headType + ".");
+ return;
+ }
+ TCon con;
+ try {
+ con = Environments.getTypeConstructorName(environment, headType.name);
+ } catch (AmbiguousNameException e1) {
+ errorLog.log(headType.location, e1.getMessage());
+ return;
+ }
+ if(con == null) {
+ errorLog.log(headType.location, "Couldn't resolve " + headType.name);
+ return;
+ }
+ TypeConstructor tcon = environment.getTypeConstructor(con);
+ if(tcon == null) {
+ errorLog.log(headType.location, "Didn't find type constructor for " + headType.name);
+ return;
+ }
+ if(tcon.isOpen) {
+ errorLog.log(headType.location, "Cannot derive instance for open data types.");
+ return;
+ }
+
+ // Generate
+ DInstanceAst instanceAst = new DInstanceAst(der.location, der.context, der.name, der.types);
+ ValueRepository valueDefs = new ValueRepository();
+ int cId = 0;
+ for(Constructor constructor : tcon.constructors) {
+ int l = constructor.parameterTypes.length;
+ String[] par = new String[l];
+ for(int i=0;i<l;++i) {
+ par[i] = "v" + i;
+ }
+ Expression lhs = new EApply(
+ new EVar("hashP"),
+ new EApply(new EVar(constructor.name.name), Expressions.vars(par)),
+ new EVar("accum")
+ );
+ Expression value = new EVar("accum");
+ for(int i=0;i<l;++i) {
+ value = new EApply(new EVar("hashP"),
+ new EVar(par[i]),
+ value
+ );
+ }
+ if(tcon.constructors.length > 1)
+ value = new EApply(new EVar("hashP"),
+ new ELiteral(new IntegerConstant(cId)),
+ value
+ );
+
+ try {
+ DValueAst valueAst = new DValueAst(lhs, value);
+ valueAst.setLocationDeep(der.location);
+ valueDefs.add(valueAst);
+ } catch (NotPatternException e) {
+ errorLog.log(e.getExpression().location, "Not a pattern.");
+ }
+ ++ cId;
+ }
+ instancesAst.add(new ProcessedDInstanceAst(instanceAst, valueDefs));
+ }
+
+}