]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/planning/QueryPlanningContext.java
CHR query translation and support for assignment in CHR bodies
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / elaboration / chr / planning / QueryPlanningContext.java
1 package org.simantics.scl.compiler.elaboration.chr.planning;
2
3 import java.util.ArrayList;
4
5 import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
6 import org.simantics.scl.compiler.compilation.CompilationContext;
7 import org.simantics.scl.compiler.elaboration.chr.CHRLiteral;
8 import org.simantics.scl.compiler.elaboration.chr.plan.AccessFactOp;
9 import org.simantics.scl.compiler.elaboration.chr.plan.ClaimOp;
10 import org.simantics.scl.compiler.elaboration.chr.plan.ExecuteOp;
11 import org.simantics.scl.compiler.elaboration.chr.plan.MatchOp;
12 import org.simantics.scl.compiler.elaboration.chr.plan.PlanOp;
13 import org.simantics.scl.compiler.elaboration.chr.planning.items.CheckPrePlanItem;
14 import org.simantics.scl.compiler.elaboration.chr.planning.items.EqualsPrePlanItem;
15 import org.simantics.scl.compiler.elaboration.chr.planning.items.GenericPrePlanItem;
16 import org.simantics.scl.compiler.elaboration.chr.planning.items.MemberPrePlanItem;
17 import org.simantics.scl.compiler.elaboration.chr.relations.CHRConstraint;
18 import org.simantics.scl.compiler.elaboration.chr.relations.SpecialCHRRelation;
19 import org.simantics.scl.compiler.elaboration.expressions.EApplyType;
20 import org.simantics.scl.compiler.elaboration.expressions.EConstant;
21 import org.simantics.scl.compiler.elaboration.expressions.EExternalConstant;
22 import org.simantics.scl.compiler.elaboration.expressions.ELiteral;
23 import org.simantics.scl.compiler.elaboration.expressions.EVariable;
24 import org.simantics.scl.compiler.elaboration.expressions.Expression;
25 import org.simantics.scl.compiler.elaboration.expressions.Variable;
26 import org.simantics.scl.compiler.errors.Locations;
27
28 import gnu.trove.impl.Constants;
29 import gnu.trove.map.hash.TObjectIntHashMap;
30 import gnu.trove.procedure.TIntProcedure;
31 import gnu.trove.set.hash.TIntHashSet;
32
33 public class QueryPlanningContext {
34     CompilationContext compilationContext;
35     public PlanPriorityQueue priorityQueue = new PlanPriorityQueue();
36     ArrayList<Variable> variables;
37     TObjectIntHashMap<Variable> variableMap;
38     ArrayList<ArrayList<PrePlanItem>> itemsContainingVariable;
39     ArrayList<PlanOp> planOps = new ArrayList<PlanOp>(); 
40     
41     public QueryPlanningContext(CompilationContext compilationContext, Variable[] variables) {
42         this.compilationContext = compilationContext;
43         this.variables = new ArrayList<Variable>(variables.length*2);
44         this.variableMap = new TObjectIntHashMap<Variable>(variables.length, Constants.DEFAULT_LOAD_FACTOR, -1);
45         itemsContainingVariable = new ArrayList<ArrayList<PrePlanItem>>(variables.length*2);
46         for(Variable variable : variables)
47             addVariable(variable);
48     }
49     
50     private void addVariable(Variable variable) {
51         int id = variables.size();
52         variables.add(variable);
53         variableMap.put(variable, id);
54         itemsContainingVariable.add(new ArrayList<PrePlanItem>(2));
55     }
56
57     public void add(CHRLiteral literal, int secondaryPriority) {
58         if(literal.relation instanceof SpecialCHRRelation) {
59             switch((SpecialCHRRelation)literal.relation) {
60             case CHECK:
61                 addCheck(literal.location, literal.parameters[0], secondaryPriority);
62                 return;
63             case EQUALS:
64                 addGenericEquals(literal.location, literal.parameters[0], literal.parameters[1], secondaryPriority);
65                 return;
66             case MEMBER:
67                 addMember(literal.location, literal.parameters[0], literal.parameters[1], secondaryPriority);
68                 return;
69             case ASSIGN:
70                 throw new InternalCompilerError(literal.location, "ASSIGN constraint is not allowed in query compilation.");
71             case EXECUTE:
72                 throw new InternalCompilerError(literal.location, "EXECUTE constraint is not allowed in query compilation.");
73             }
74         }
75         
76         addGenericConstraint(literal, secondaryPriority);
77     }
78     
79     private TIntHashSet getVars(Expression expression, int initialCapacity) {
80         TIntHashSet variableSet = new TIntHashSet(initialCapacity);
81         expression.collectVars(variableMap, variableSet);
82         return variableSet;
83     }
84     
85     private TIntHashSet[] getVars(Expression[] expressions, int initialCapacity) {
86         TIntHashSet[] variableSets = new TIntHashSet[expressions.length];
87         for(int i=0;i<expressions.length;++i)
88             variableSets[i] = getVars(expressions[i], initialCapacity);
89         return variableSets;
90     }
91     
92     /**
93      * Returns true, if the expression is so simple, it does not involve any computation.
94      */
95     private static boolean isSimpleExpression(Expression expression) {
96         while(expression instanceof EApplyType)
97             expression = ((EApplyType)expression).getExpression();
98         return expression instanceof EVariable 
99                 || expression instanceof EConstant
100                 || expression instanceof ELiteral
101                 || expression instanceof EExternalConstant;
102     }
103     
104     private Expression toSimpleExpression(Expression expression, int secondaryPriority) {
105         if(isSimpleExpression(expression))        
106             return expression;
107         else {
108             Variable temp = new Variable("temp", expression.getType());
109             addVariable(temp);
110             addOneSidedEquals(expression.location, new EVariable(temp), expression, secondaryPriority);
111             return new EVariable(temp);
112         }
113     }
114     
115     private Expression[] toSimpleExpressions(Expression[] expressions, int secondaryPriority) {
116         Expression[] result = new Expression[expressions.length];
117         for(int i=0;i<expressions.length;++i)
118             result[i] = toSimpleExpression(expressions[i], secondaryPriority);
119         return result;
120     }
121
122     private void addGenericConstraint(CHRLiteral literal, int secondaryPriority) {
123         if(literal.killAfterMatch)
124             ((CHRConstraint)literal.relation).setMayBeRemoved();
125         Expression[] parameters = toSimpleExpressions(literal.parameters, secondaryPriority);
126         add(literal.location, new GenericPrePlanItem(literal, literal.relation, parameters, getVars(parameters, 1), secondaryPriority));
127     }
128
129     private void addMember(long location, Expression p1, Expression p2, int secondaryPriority) {
130         Expression expression1 = toSimpleExpression(p1, secondaryPriority);
131         Expression expression2 = toSimpleExpression(p2, secondaryPriority);
132         add(location, new MemberPrePlanItem(expression1, expression2,
133                 getVars(expression1, 1), getVars(expression2, 1), secondaryPriority));
134     }
135     
136     private void addOneSidedEquals(long location, Expression expression1, Expression expression2, int secondaryPriority) {
137         add(location, new EqualsPrePlanItem(expression1, expression2,
138                 getVars(expression1, 1), getVars(expression2, 4), secondaryPriority));
139     }
140
141     private void addGenericEquals(long location, Expression p1, Expression p2, int secondaryPriority) {
142         if(isSimpleExpression(p1))
143             addOneSidedEquals(location, p1, p2, secondaryPriority);
144         else if(isSimpleExpression(p2))
145             addOneSidedEquals(location, p2, p1, secondaryPriority);
146         else {
147             Variable temp = new Variable("temp", p1.getType());
148             addVariable(temp);
149             addOneSidedEquals(p1.location, new EVariable(temp), p1, secondaryPriority);
150             addOneSidedEquals(p2.location, new EVariable(temp), p2, secondaryPriority);
151         }
152     }
153
154     private void addCheck(long location, Expression condition, int secondaryPriority) {
155         TIntHashSet variableSet = new TIntHashSet(4);
156         condition.collectVars(variableMap, variableSet);
157         add(location, new CheckPrePlanItem(condition, variableSet, secondaryPriority));
158     }
159
160     private void add(long location, PrePlanItem item) {
161         priorityQueue.add(item);
162         item.initializeListeners(this);
163         item.location = location;
164     }
165
166     public void listen(TIntHashSet variableSet, PrePlanItem item) {
167         variableSet.forEach(new TIntProcedure() {
168             @Override
169             public boolean execute(int variableId) {
170                 listen(variableId, item);
171                 return true;
172             }
173         });
174     }
175
176     public void listen(int variableId, PrePlanItem item) {
177         itemsContainingVariable.get(variableId).add(item);
178     }
179
180     public boolean createQueryPlan() {
181         while(!priorityQueue.isEmpty()) {
182             PrePlanItem head = priorityQueue.head();
183             if(head.primaryPriority == Double.POSITIVE_INFINITY) {
184                 compilationContext.errorLog.log(head.location, "Cannot solve the query.");
185                 return false;
186             }
187             priorityQueue.pop();
188             head.generate(this);
189         }
190         return true;
191     }
192     
193     public ArrayList<PlanOp> getPlanOps() {
194         return planOps;
195     }
196     
197     private final TIntProcedure BIND_PROCEDURE = new TIntProcedure() {
198         @Override
199         public boolean execute(int variableId) {
200             ArrayList<PrePlanItem> l = itemsContainingVariable.get(variableId);
201             for(PrePlanItem item : l)
202                 item.variableSolved(QueryPlanningContext.this, variableId);
203             l.clear();
204             return true;
205         }
206     };
207
208     public void bind(TIntHashSet variableSet) {
209         variableSet.forEach(BIND_PROCEDURE);
210     }
211
212     public void addPlanOp(PlanOp planOp) {
213         planOps.add(planOp);
214     }
215
216     public CompilationContext getCompilationContext() {
217         return compilationContext;
218     }
219
220     public void activate(CHRLiteral literal, Expression inputFact, int secondaryPriority) {
221         Variable[] variables = new Variable[literal.parameters.length];
222         for(int i=0;i<literal.parameters.length;++i)
223             variables[i] = new Variable("activeFactComponent" + i, literal.parameters[i].getType());
224         if(literal.killAfterMatch)
225             ((CHRConstraint)literal.relation).setMayBeRemoved();
226         planOps.add(new AccessFactOp(literal.location, inputFact, (CHRConstraint)literal.relation, variables, literal.killAfterMatch));
227         for(int i=0;i<literal.parameters.length;++i)
228             addOneSidedEquals(literal.parameters[i].location, new EVariable(variables[i]), literal.parameters[i], secondaryPriority);
229     }
230     
231     public void addInitFact(CHRConstraint initConstraint, Expression inputFact) {
232         planOps.add(new AccessFactOp(Locations.NO_LOCATION, inputFact, initConstraint, Variable.EMPTY_ARRAY, false));
233     }
234
235     public void claim(QueryPlanningContext context, CHRLiteral literal) {
236         if(literal.relation instanceof CHRConstraint) {
237             CHRConstraint constraint = (CHRConstraint)literal.relation;
238             addPlanOp(new ClaimOp(literal.location, constraint, literal.parameters));
239         }
240         else if(literal.relation instanceof SpecialCHRRelation) {
241             switch((SpecialCHRRelation)literal.relation) {
242             case EXECUTE:
243                 addPlanOp(new ExecuteOp(literal.location, literal.parameters[0]));
244                 break;
245             case ASSIGN:
246                 addPlanOp(new MatchOp(literal.location, literal.parameters[1], literal.parameters[0]));
247                 break;
248             default:
249                 context.getCompilationContext().errorLog.log(
250                         literal.location,
251                         "Cannot enforce this constraint.");
252             }
253         }
254     }
255
256 }