1 package org.simantics.scl.compiler.elaboration.query;
3 import java.util.ArrayList;
6 import org.simantics.scl.compiler.elaboration.contexts.ReplaceContext;
7 import org.simantics.scl.compiler.elaboration.contexts.TypingContext;
8 import org.simantics.scl.compiler.elaboration.expressions.ESimpleLet;
9 import org.simantics.scl.compiler.elaboration.expressions.EVariable;
10 import org.simantics.scl.compiler.elaboration.expressions.Expression;
11 import org.simantics.scl.compiler.elaboration.expressions.QueryTransformer;
12 import org.simantics.scl.compiler.elaboration.expressions.Variable;
13 import org.simantics.scl.compiler.elaboration.expressions.VariableProcedure;
14 import org.simantics.scl.compiler.elaboration.java.EqRelation;
15 import org.simantics.scl.compiler.elaboration.query.compilation.ConstraintCollectionContext;
16 import org.simantics.scl.compiler.elaboration.query.compilation.DerivateException;
17 import org.simantics.scl.compiler.elaboration.query.compilation.EnforcingContext;
18 import org.simantics.scl.compiler.elaboration.query.compilation.ExpressionConstraint;
19 import org.simantics.scl.compiler.elaboration.query.compilation.RelationConstraint;
20 import org.simantics.scl.compiler.elaboration.relations.CompositeRelation;
21 import org.simantics.scl.compiler.elaboration.relations.LocalRelation;
22 import org.simantics.scl.compiler.elaboration.relations.SCLRelation;
23 import org.simantics.scl.compiler.errors.Locations;
24 import org.simantics.scl.compiler.types.TVar;
25 import org.simantics.scl.compiler.types.Type;
26 import org.simantics.scl.compiler.types.Types;
28 import gnu.trove.map.hash.THashMap;
29 import gnu.trove.map.hash.TIntObjectHashMap;
30 import gnu.trove.set.hash.TIntHashSet;
32 public class QAtom extends Query {
33 public SCLRelation relation;
34 public Type[] typeParameters;
35 public Expression[] parameters;
37 public QAtom(SCLRelation relation, Expression ... parameters) {
38 this.relation = relation;
39 this.parameters = parameters;
42 public QAtom(SCLRelation relation, Type[] typeParameters, Expression ... parameters) {
43 this.relation = relation;
44 this.typeParameters = typeParameters;
45 this.parameters = parameters;
49 public void checkType(TypingContext context) {
51 TVar[] typeVariables = relation.getTypeVariables();
52 typeParameters = new Type[typeVariables.length];
53 for(int i=0;i<typeVariables.length;++i)
54 typeParameters[i] = Types.metaVar(typeVariables[i].getKind());
56 // Check parameter types
57 Type[] parameterTypes = relation.getParameterTypes();
58 if(parameterTypes.length != parameters.length)
59 context.getErrorLog().log(location, "Relation is applied with wrong number of parameters.");
61 for(int i=0;i<parameters.length;++i)
62 parameters[i] = parameters[i]
63 .checkType(context, parameterTypes[i].replace(typeVariables, typeParameters));
66 public Expression generateEnforce(EnforcingContext context) {
67 Variable[] variables = new Variable[parameters.length];
68 for(int i=0;i<variables.length;++i)
69 if(parameters[i] instanceof EVariable)
70 variables[i] = ((EVariable)parameters[i]).getVariable();
72 variables[i] = new Variable("p" + i, parameters[i].getType());
73 Expression result = relation.generateEnforce(location, context, typeParameters, variables);
74 for(int i=variables.length-1;i>=0;--i)
75 if(!(parameters[i] instanceof EVariable))
76 result = new ESimpleLet(
84 private static class VariableMaskProcedure implements VariableProcedure {
85 ConstraintCollectionContext context;
86 long requiredVariablesMask = 0L;
88 public VariableMaskProcedure(ConstraintCollectionContext context) {
89 this.context = context;
93 public void execute(long location, Variable variable) {
94 int id = context.getVariableMap().get(variable);
96 requiredVariablesMask |= 1L << id;
101 public void collectConstraints(ConstraintCollectionContext context) {
103 // Analyze parameters and find required and optional variables
104 VariableMaskProcedure procedure = new VariableMaskProcedure(context);
105 int[] optionalVariableByParameter = new int[parameters.length];
106 Variable[] varParameters = new Variable[parameters.length];
107 for(int i=0;i<parameters.length;++i) {
108 Expression parameter = parameters[i];
109 if(parameter instanceof EVariable) {
110 Variable variable = ((EVariable)parameter).getVariable();
111 optionalVariableByParameter[i] = context.getVariableMap().get(variable);
112 varParameters[i] = variable;
115 Variable temp = new Variable("temp", parameter.getType());
116 varParameters[i] = temp;
117 if(parameter.isPattern(0)) {
118 int tempId = context.addVariable(temp);
119 context.addConstraint(new ExpressionConstraint(context, temp, parameter, true));
120 optionalVariableByParameter[i] = tempId;
123 optionalVariableByParameter[i] = -1;
124 parameter.forVariableUses(procedure);
129 // Combine required and optional variables
130 TIntHashSet allVariablesSet = new TIntHashSet();
131 for(int v : optionalVariableByParameter)
133 allVariablesSet.add(v);
135 context.addConstraint(new RelationConstraint(allVariablesSet.toArray(), varParameters, this,
136 optionalVariableByParameter, procedure.requiredVariablesMask));
137 } catch(Exception e) {
138 context.getQueryCompilationContext().getTypingContext().getErrorLog().log(location, e);
143 public Query replace(ReplaceContext context) {
144 Type[] newTypeParameters;
145 if(typeParameters == null)
146 newTypeParameters = null;
148 newTypeParameters = new Type[typeParameters.length];
149 for(int i=0;i<typeParameters.length;++i)
150 newTypeParameters[i] = typeParameters[i].replace(context.tvarMap);
152 return new QAtom(relation,
154 Expression.replace(context, parameters));
157 @SuppressWarnings("unchecked")
159 public Diff[] derivate(THashMap<LocalRelation, Diffable> diffables) throws DerivateException {
160 Diffable diffable = diffables.get(relation);
161 if(diffable == null) {
162 if(relation instanceof CompositeRelation &&
163 containsReferenceTo((CompositeRelation)relation,
164 (THashMap<SCLRelation, Diffable>)(THashMap)diffables))
165 throw new DerivateException(location);
169 Query[] eqs = new Query[parameters.length];
170 for(int i=0;i<parameters.length;++i) {
171 QAtom eq = new QAtom(EqRelation.INSTANCE, new Expression[] {
172 new EVariable(diffable.parameters[i]),
175 eq.setLocationDeep(location);
176 eq.typeParameters = new Type[] {parameters[i].getType()};
179 return new Diff[] { new Diff(diffable.id, new QConjunction(eqs)) };
183 private static boolean containsReferenceTo(
184 CompositeRelation relation,
185 THashMap<SCLRelation, Diffable> diffables) {
186 for(SCLRelation r : relation.getSubrelations())
187 if(diffables.containsKey(r))
189 else if(r instanceof CompositeRelation &&
190 containsReferenceTo((CompositeRelation)r, diffables))
196 public Query removeRelations(Set<SCLRelation> relations) {
197 if(relations.contains(relation))
204 public void setLocationDeep(long loc) {
205 if(location == Locations.NO_LOCATION) {
207 for(Expression parameter : parameters)
208 parameter.setLocationDeep(loc);
213 public void accept(QueryVisitor visitor) {
218 public void splitToPhases(TIntObjectHashMap<ArrayList<Query>> result) {
219 int phase = relation.getPhase();
220 ArrayList<Query> list = result.get(phase);
222 list = new ArrayList<Query>();
223 result.put(phase, list);
229 public Query accept(QueryTransformer transformer) {
230 return transformer.transform(this);