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.map.hash.TObjectIntHashMap;
31 import gnu.trove.set.hash.THashSet;
32 import gnu.trove.set.hash.TIntHashSet;
34 public class QAtom extends Query {
35 public SCLRelation relation;
36 public Type[] typeParameters;
37 public Expression[] parameters;
39 public QAtom(SCLRelation relation, Expression ... parameters) {
40 this.relation = relation;
41 this.parameters = parameters;
44 public QAtom(SCLRelation relation, Type[] typeParameters, Expression ... parameters) {
45 this.relation = relation;
46 this.typeParameters = typeParameters;
47 this.parameters = parameters;
51 public void collectFreeVariables(THashSet<Variable> vars) {
52 for(Expression parameter : parameters)
53 parameter.collectFreeVariables(vars);
57 public void checkType(TypingContext context) {
59 TVar[] typeVariables = relation.getTypeVariables();
60 typeParameters = new Type[typeVariables.length];
61 for(int i=0;i<typeVariables.length;++i)
62 typeParameters[i] = Types.metaVar(typeVariables[i].getKind());
64 // Check parameter types
65 Type[] parameterTypes = relation.getParameterTypes();
66 if(parameterTypes.length != parameters.length)
67 context.getErrorLog().log(location, "Relation is applied with wrong number of parameters.");
69 for(int i=0;i<parameters.length;++i)
70 parameters[i] = parameters[i]
71 .checkType(context, parameterTypes[i].replace(typeVariables, typeParameters));
74 public Expression generateEnforce(EnforcingContext context) {
75 Variable[] variables = new Variable[parameters.length];
76 for(int i=0;i<variables.length;++i)
77 if(parameters[i] instanceof EVariable)
78 variables[i] = ((EVariable)parameters[i]).getVariable();
80 variables[i] = new Variable("p" + i, parameters[i].getType());
81 Expression result = relation.generateEnforce(location, context, typeParameters, variables);
82 for(int i=variables.length-1;i>=0;--i)
83 if(!(parameters[i] instanceof EVariable))
84 result = new ESimpleLet(
92 private static class VariableMaskProcedure implements VariableProcedure {
93 ConstraintCollectionContext context;
94 long requiredVariablesMask = 0L;
96 public VariableMaskProcedure(ConstraintCollectionContext context) {
97 this.context = context;
101 public void execute(long location, Variable variable) {
102 int id = context.getVariableMap().get(variable);
104 requiredVariablesMask |= 1L << id;
109 public void collectConstraints(ConstraintCollectionContext context) {
111 // Analyze parameters and find required and optional variables
112 VariableMaskProcedure procedure = new VariableMaskProcedure(context);
113 int[] optionalVariableByParameter = new int[parameters.length];
114 Variable[] varParameters = new Variable[parameters.length];
115 for(int i=0;i<parameters.length;++i) {
116 Expression parameter = parameters[i];
117 if(parameter instanceof EVariable) {
118 Variable variable = ((EVariable)parameter).getVariable();
119 optionalVariableByParameter[i] = context.getVariableMap().get(variable);
120 varParameters[i] = variable;
123 Variable temp = new Variable("temp", parameter.getType());
124 varParameters[i] = temp;
125 if(parameter.isPattern(0)) {
126 int tempId = context.addVariable(temp);
127 context.addConstraint(new ExpressionConstraint(context, temp, parameter, true));
128 optionalVariableByParameter[i] = tempId;
131 optionalVariableByParameter[i] = -1;
132 parameter.forVariables(procedure);
137 // Combine required and optional variables
138 TIntHashSet allVariablesSet = new TIntHashSet();
139 for(int v : optionalVariableByParameter)
141 allVariablesSet.add(v);
143 context.addConstraint(new RelationConstraint(allVariablesSet.toArray(), varParameters, this,
144 optionalVariableByParameter, procedure.requiredVariablesMask));
145 } catch(Exception e) {
146 context.getQueryCompilationContext().getTypingContext().getErrorLog().log(location, e);
150 private static void collectRefs(SCLRelation relation, TObjectIntHashMap<Object> allRefs,
152 if(relation instanceof CompositeRelation) {
153 for(SCLRelation subrelation : ((CompositeRelation) relation).getSubrelations())
154 collectRefs(subrelation, allRefs, refs);
157 int id = allRefs.get(relation);
164 public void collectRefs(TObjectIntHashMap<Object> allRefs,
166 collectRefs(relation, allRefs, refs);
167 for(Expression parameter : parameters)
168 parameter.collectRefs(allRefs, refs);
172 public void collectVars(TObjectIntHashMap<Variable> allVars,
174 for(Expression parameter : parameters)
175 parameter.collectVars(allVars, vars);
179 public Query replace(ReplaceContext context) {
180 Type[] newTypeParameters;
181 if(typeParameters == null)
182 newTypeParameters = null;
184 newTypeParameters = new Type[typeParameters.length];
185 for(int i=0;i<typeParameters.length;++i)
186 newTypeParameters[i] = typeParameters[i].replace(context.tvarMap);
188 return new QAtom(relation,
190 Expression.replace(context, parameters));
193 @SuppressWarnings("unchecked")
195 public Diff[] derivate(THashMap<LocalRelation, Diffable> diffables) throws DerivateException {
196 Diffable diffable = diffables.get(relation);
197 if(diffable == null) {
198 if(relation instanceof CompositeRelation &&
199 containsReferenceTo((CompositeRelation)relation,
200 (THashMap<SCLRelation, Diffable>)(THashMap)diffables))
201 throw new DerivateException(location);
205 Query[] eqs = new Query[parameters.length];
206 for(int i=0;i<parameters.length;++i) {
207 QAtom eq = new QAtom(EqRelation.INSTANCE, new Expression[] {
208 new EVariable(diffable.parameters[i]),
211 eq.setLocationDeep(location);
212 eq.typeParameters = new Type[] {parameters[i].getType()};
215 return new Diff[] { new Diff(diffable.id, new QConjunction(eqs)) };
219 private static boolean containsReferenceTo(
220 CompositeRelation relation,
221 THashMap<SCLRelation, Diffable> diffables) {
222 for(SCLRelation r : relation.getSubrelations())
223 if(diffables.containsKey(r))
225 else if(r instanceof CompositeRelation &&
226 containsReferenceTo((CompositeRelation)r, diffables))
232 public Query removeRelations(Set<SCLRelation> relations) {
233 if(relations.contains(relation))
240 public void setLocationDeep(long loc) {
241 if(location == Locations.NO_LOCATION) {
243 for(Expression parameter : parameters)
244 parameter.setLocationDeep(loc);
249 public void accept(QueryVisitor visitor) {
254 public void forVariables(VariableProcedure procedure) {
255 for(Expression parameter : parameters)
256 parameter.forVariables(procedure);
260 public void splitToPhases(TIntObjectHashMap<ArrayList<Query>> result) {
261 int phase = relation.getPhase();
262 ArrayList<Query> list = result.get(phase);
264 list = new ArrayList<Query>();
265 result.put(phase, list);
271 public Query accept(QueryTransformer transformer) {
272 return transformer.transform(this);