--- /dev/null
+package org.simantics.scl.compiler.elaboration.relations;
+
+import java.util.ArrayList;
+
+import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
+import org.simantics.scl.compiler.elaboration.contexts.ReplaceContext;
+import org.simantics.scl.compiler.elaboration.expressions.EVariable;
+import org.simantics.scl.compiler.elaboration.expressions.Expression;
+import org.simantics.scl.compiler.elaboration.expressions.Variable;
+import org.simantics.scl.compiler.elaboration.query.QExists;
+import org.simantics.scl.compiler.elaboration.query.Query;
+import org.simantics.scl.compiler.elaboration.query.compilation.EnforcingContext;
+import org.simantics.scl.compiler.elaboration.query.compilation.QueryCompilationContext;
+import org.simantics.scl.compiler.elaboration.query.compilation.UnsolvableQueryException;
+import org.simantics.scl.compiler.internal.parsing.Symbol;
+import org.simantics.scl.compiler.types.TVar;
+import org.simantics.scl.compiler.types.Type;
+import org.simantics.scl.compiler.types.Types;
+
+public class ConcreteRelation extends Symbol implements SCLRelation {
+
+ public final String name;
+ public Variable[] parameters;
+ private int requiredVariablesMask = 0xffffffff;
+
+ public static class QuerySection {
+ public final int pattern;
+ public final double selectivity;
+ public final Variable[] existentials;
+ public final Query query;
+ public Type effect;
+
+ public QuerySection(int pattern, double selectivity, Variable[] existentials, Query query) {
+ this.pattern = pattern;
+ this.selectivity = selectivity;
+ this.existentials = existentials;
+ this.query = query;
+ }
+ }
+
+ private ArrayList<QuerySection> sections = new ArrayList<QuerySection>(4);
+ public Query enforceSection;
+ public Type writingEffect;
+
+ Type[] parameterTypes;
+ public TVar[] typeVariables = TVar.EMPTY_ARRAY;
+ public int phase;
+
+ public ConcreteRelation(String name) {
+ this.name = name;
+ }
+
+ public void addSection(int pattern, double selectivity, Variable[] existentials, Query query) {
+ sections.add(new QuerySection(pattern, selectivity, existentials, query));
+ requiredVariablesMask &= pattern;
+ }
+
+ public QuerySection getSection(int pattern) {
+ for(QuerySection section : sections)
+ if((section.pattern | pattern) == pattern)
+ return section;
+ return null;
+ }
+
+ public ArrayList<QuerySection> getSections() {
+ return sections;
+ }
+
+ @Override
+ public TVar[] getTypeVariables() {
+ return typeVariables;
+ }
+
+ @Override
+ public Type[] getParameterTypes() {
+ if(parameterTypes == null) {
+ parameterTypes = new Type[parameters.length];
+ for(int i=0;i<parameters.length;++i)
+ parameterTypes[i] = Types.canonical(parameters[i].getType());
+ }
+ return parameterTypes;
+ }
+
+ @Override
+ public int getPhase() {
+ return phase;
+ }
+
+ @Override
+ public double getSelectivity(int boundVariables) {
+ QuerySection section = getSection(boundVariables);
+ if(section == null)
+ return Double.POSITIVE_INFINITY;
+ else
+ return section.selectivity;
+ }
+
+ @Override
+ public int getRequiredVariablesMask() {
+ return requiredVariablesMask;
+ }
+
+ @Override
+ public void generate(long location,
+ QueryCompilationContext context,
+ Type[] typeParameters, Variable[] parameters, int boundVariables) {
+ QuerySection section = getSection(boundVariables);
+ ReplaceContext replaceContext = new ReplaceContext(context.getTypingContext());
+ ArrayList<Variable> freeVariables = new ArrayList<Variable>(parameters.length);
+ for(int i=0;i<parameters.length;++i) {
+ replaceContext.varMap.put(this.parameters[i], new EVariable(parameters[i]));
+ if(((boundVariables>>i)&1) == 0)
+ freeVariables.add(parameters[i]);
+ }
+ for(Variable variable : section.existentials) {
+ Variable newVariable = new Variable(variable.getName(), variable.getType());
+ replaceContext.varMap.put(variable, new EVariable(newVariable));
+ freeVariables.add(newVariable);
+ }
+ try {
+ new QExists(freeVariables, section.query.replace(replaceContext)).generate(context);
+ } catch (UnsolvableQueryException e) {
+ throw new InternalCompilerError(e);
+ }
+ }
+
+ @Override
+ public Expression generateEnforce(long location,
+ EnforcingContext context,
+ Type[] typeParameters,
+ Variable[] parameters) {
+ if(this.typeVariables.length != typeParameters.length)
+ throw new InternalCompilerError(location, "Invalid number of type parameters given.");
+ if(this.parameters.length != parameters.length)
+ throw new InternalCompilerError(location, "Invalid number of parameters given.");
+ ReplaceContext replaceContext = new ReplaceContext(context.getTypingContext());
+ for(int i=0;i<this.parameters.length;++i)
+ replaceContext.varMap.put(this.parameters[i], new EVariable(parameters[i]));
+ for(int i=0;i<this.typeVariables.length;++i)
+ replaceContext.tvarMap.put(this.typeVariables[i], typeParameters[i]);
+ Query enforceSectionCopy = enforceSection.replace(replaceContext);
+ return enforceSectionCopy.generateEnforce(context);
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+
+}