--- /dev/null
+package org.simantics.scl.compiler.elaboration.relations;
+
+import static org.simantics.scl.compiler.elaboration.expressions.Expressions.*;
+
+import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
+import org.simantics.scl.compiler.common.names.Name;
+import org.simantics.scl.compiler.elaboration.expressions.ERuleset;
+import org.simantics.scl.compiler.elaboration.expressions.EVariable;
+import org.simantics.scl.compiler.elaboration.expressions.Expressions;
+import org.simantics.scl.compiler.elaboration.expressions.Variable;
+import org.simantics.scl.compiler.elaboration.query.compilation.QueryCompilationContext;
+import org.simantics.scl.compiler.types.TVar;
+import org.simantics.scl.compiler.types.Type;
+import org.simantics.scl.compiler.types.Types;
+import org.simantics.scl.compiler.types.kinds.Kinds;
+
+public class LocalRelation extends AbstractRelation {
+ String name;
+ Type[] parameterTypes;
+ public Variable table;
+
+ public LocalRelation(String name, int arity) {
+ this.name = name;
+ this.parameterTypes = new Type[arity];
+ for(int i=0;i<arity;++i)
+ parameterTypes[i] = Types.metaVar(Kinds.STAR);
+ createTable();
+ }
+
+ public LocalRelation(String name, Type[] parameterTypes) {
+ this.name = name;
+ this.parameterTypes = parameterTypes;
+ createTable();
+ }
+
+ private void createTable() {
+ this.table = newVar("table" + name,
+ Types.apply(ERuleset.MSet, Types.tuple(parameterTypes)));
+ }
+
+ public int getArity() {
+ return parameterTypes.length;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public TVar[] getTypeVariables() {
+ return TVar.EMPTY_ARRAY;
+ }
+
+ @Override
+ public Type[] getParameterTypes() {
+ return parameterTypes;
+ }
+
+ @Override
+ public double getSelectivity(int boundVariabes) {
+ double s = 0.95;
+ for(int i=0;i<parameterTypes.length;++i,boundVariabes>>=1)
+ if( (boundVariabes&1) == 0 )
+ s *= 10.0;
+ return s;
+ }
+
+ @Override
+ public int getRequiredVariablesMask() {
+ return 0;
+ }
+
+ private static final Name MSet_contains = Name.create("MSet", "contains");
+ private static final Name EQ = Name.create("Prelude", "==");
+ @Override
+ public void generate(long location,
+ QueryCompilationContext context,
+ Type[] typeParameters, Variable[] parameters, int boundVariables) {
+ if(table == null)
+ throw new InternalCompilerError(location, "Variable table is undefined.");
+ if(boundVariables + 1 == 1 << parameters.length)
+ context.condition(apply(context, Types.PROC,
+ MSet_contains, Types.tuple(parameterTypes),
+ var(table),
+ tuple(vars(parameters))
+ ));
+ else {
+ Variable[] aux = new Variable[parameters.length];
+ for(int i=0;i<parameters.length;++i)
+ if(((boundVariables>>i)&1) == 1)
+ aux[i] = new Variable("aux_" + parameters[i].getName(), parameters[i].getType());
+ else
+ aux[i] = parameters[i];
+ Variable row = new Variable("row", Types.tuple(parameterTypes));
+ for(int i=0;i<parameters.length;++i)
+ if(((boundVariables>>i)&1) == 1)
+ context.condition(apply(context, Types.NO_EFFECTS,
+ EQ, parameterTypes[i],
+ context.getEvidence(location, Types.pred(Types.EQ, parameterTypes[i])),
+ var(aux[i]),
+ var(parameters[i])
+ ));
+ context.match(Expressions.tuple(Expressions.vars(aux)), new EVariable(row), false);
+ context.iterateMSet(row, new EVariable(table));
+ }
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+}