]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/query/QAtom.java
migrated to svn revision 33108
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / elaboration / query / QAtom.java
1 package org.simantics.scl.compiler.elaboration.query;
2
3 import java.util.ArrayList;
4 import java.util.Set;
5
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;
27
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;
33
34 public class QAtom extends Query {
35     public SCLRelation relation;
36     public Type[] typeParameters;
37     public Expression[] parameters;
38
39     public QAtom(SCLRelation relation, Expression ... parameters) {
40         this.relation = relation;
41         this.parameters = parameters;
42     }
43
44     public QAtom(SCLRelation relation, Type[] typeParameters, Expression ... parameters) {
45         this.relation = relation;
46         this.typeParameters = typeParameters;
47         this.parameters = parameters;
48     }
49
50     @Override
51     public void collectFreeVariables(THashSet<Variable> vars) {
52         for(Expression parameter : parameters)
53             parameter.collectFreeVariables(vars);
54     }
55
56     @Override
57     public void checkType(TypingContext context) {
58         // Type parameters
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());
63
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.");
68         else
69             for(int i=0;i<parameters.length;++i)
70                 parameters[i] = parameters[i]
71                         .checkType(context, parameterTypes[i].replace(typeVariables, typeParameters));
72     }
73
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();
79             else
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(
85                         variables[i],
86                         parameters[i],
87                         result
88                         );
89         return result;
90     }
91
92     private static class VariableMaskProcedure implements VariableProcedure {
93         ConstraintCollectionContext context;
94         long requiredVariablesMask = 0L;
95
96         public VariableMaskProcedure(ConstraintCollectionContext context) {
97             this.context = context;
98         }
99
100         @Override
101         public void execute(long location, Variable variable) {
102             int id = context.getVariableMap().get(variable);
103             if(id >= 0)
104                 requiredVariablesMask |= 1L << id;
105         }
106     }
107
108     @Override
109     public void collectConstraints(ConstraintCollectionContext context) {
110         try {
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;
121                 }
122                 else {
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;
129                     }
130                     else {
131                         optionalVariableByParameter[i] = -1;
132                         parameter.forVariables(procedure);
133                     }
134                 }
135             }
136
137             // Combine required and optional variables
138             TIntHashSet allVariablesSet = new TIntHashSet();
139             for(int v : optionalVariableByParameter)
140                 if(v >= 0)
141                     allVariablesSet.add(v);
142
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);
147         }
148     }
149
150     private static void collectRefs(SCLRelation relation, TObjectIntHashMap<Object> allRefs,
151             TIntHashSet refs) {
152         if(relation instanceof CompositeRelation) {
153             for(SCLRelation subrelation : ((CompositeRelation) relation).getSubrelations())
154                 collectRefs(subrelation, allRefs, refs);
155         }
156         else {
157             int id = allRefs.get(relation);
158             if(id >= 0)
159                 refs.add(id);
160         }
161     }
162
163     @Override
164     public void collectRefs(TObjectIntHashMap<Object> allRefs,
165             TIntHashSet refs) {
166         collectRefs(relation, allRefs, refs);
167         for(Expression parameter : parameters)
168             parameter.collectRefs(allRefs, refs);
169     }
170
171     @Override
172     public void collectVars(TObjectIntHashMap<Variable> allVars,
173             TIntHashSet vars) {
174         for(Expression parameter : parameters)
175             parameter.collectVars(allVars, vars);
176     }
177
178     @Override
179     public Query replace(ReplaceContext context) {
180         Type[] newTypeParameters;
181         if(typeParameters == null)
182             newTypeParameters = null;
183         else {
184             newTypeParameters = new Type[typeParameters.length];
185             for(int i=0;i<typeParameters.length;++i)
186                 newTypeParameters[i] = typeParameters[i].replace(context.tvarMap);
187         }
188         return new QAtom(relation,
189                 newTypeParameters,
190                 Expression.replace(context, parameters));
191     }
192
193     @SuppressWarnings("unchecked")
194     @Override
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);
202             return NO_DIFF;
203         }
204         else {
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]),
209                         parameters[i]
210                 });
211                 eq.setLocationDeep(location);
212                 eq.typeParameters = new Type[] {parameters[i].getType()};
213                 eqs[i] = eq;
214             }
215             return new Diff[] { new Diff(diffable.id, new QConjunction(eqs)) };
216         }
217     }
218
219     private static boolean containsReferenceTo(
220             CompositeRelation relation,
221             THashMap<SCLRelation, Diffable> diffables) {
222         for(SCLRelation r : relation.getSubrelations())
223             if(diffables.containsKey(r))
224                 return true;
225             else if(r instanceof CompositeRelation &&
226                     containsReferenceTo((CompositeRelation)r, diffables))
227                 return true;
228         return false;
229     }
230
231     @Override
232     public Query removeRelations(Set<SCLRelation> relations) {
233         if(relations.contains(relation))
234             return EMPTY_QUERY;
235         else
236             return this;
237     }
238
239     @Override
240     public void setLocationDeep(long loc) {
241         if(location == Locations.NO_LOCATION) {
242             location = loc;
243             for(Expression parameter : parameters)
244                 parameter.setLocationDeep(loc);
245         }
246     }
247
248     @Override
249     public void accept(QueryVisitor visitor) {
250         visitor.visit(this);
251     }
252
253     @Override
254     public void forVariables(VariableProcedure procedure) {
255         for(Expression parameter : parameters)
256             parameter.forVariables(procedure);
257     }
258
259     @Override
260     public void splitToPhases(TIntObjectHashMap<ArrayList<Query>> result) {
261         int phase = relation.getPhase();
262         ArrayList<Query> list = result.get(phase);
263         if(list == null) {
264             list = new ArrayList<Query>();
265             result.put(phase, list);
266         }
267         list.add(this);
268     }
269
270     @Override
271     public Query accept(QueryTransformer transformer) {
272         return transformer.transform(this);
273     }
274
275 }