1 package org.simantics.scl.compiler.elaboration.chr.planning;
\r
3 import java.util.ArrayList;
\r
5 import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
\r
6 import org.simantics.scl.compiler.compilation.CompilationContext;
\r
7 import org.simantics.scl.compiler.elaboration.chr.CHRLiteral;
\r
8 import org.simantics.scl.compiler.elaboration.chr.plan.AccessFactOp;
\r
9 import org.simantics.scl.compiler.elaboration.chr.plan.ClaimOp;
\r
10 import org.simantics.scl.compiler.elaboration.chr.plan.ExecuteOp;
\r
11 import org.simantics.scl.compiler.elaboration.chr.plan.PlanOp;
\r
12 import org.simantics.scl.compiler.elaboration.chr.planning.items.CheckPrePlanItem;
\r
13 import org.simantics.scl.compiler.elaboration.chr.planning.items.EqualsPrePlanItem;
\r
14 import org.simantics.scl.compiler.elaboration.chr.planning.items.GenericPrePlanItem;
\r
15 import org.simantics.scl.compiler.elaboration.chr.planning.items.MemberPrePlanItem;
\r
16 import org.simantics.scl.compiler.elaboration.chr.relations.CHRConstraint;
\r
17 import org.simantics.scl.compiler.elaboration.chr.relations.SpecialCHRRelation;
\r
18 import org.simantics.scl.compiler.elaboration.expressions.EApplyType;
\r
19 import org.simantics.scl.compiler.elaboration.expressions.EConstant;
\r
20 import org.simantics.scl.compiler.elaboration.expressions.EExternalConstant;
\r
21 import org.simantics.scl.compiler.elaboration.expressions.ELiteral;
\r
22 import org.simantics.scl.compiler.elaboration.expressions.EVariable;
\r
23 import org.simantics.scl.compiler.elaboration.expressions.Expression;
\r
24 import org.simantics.scl.compiler.elaboration.expressions.Variable;
\r
26 import gnu.trove.impl.Constants;
\r
27 import gnu.trove.map.hash.TObjectIntHashMap;
\r
28 import gnu.trove.procedure.TIntProcedure;
\r
29 import gnu.trove.set.hash.TIntHashSet;
\r
31 public class QueryPlanningContext {
\r
32 CompilationContext compilationContext;
\r
33 public PlanPriorityQueue priorityQueue = new PlanPriorityQueue();
\r
34 ArrayList<Variable> variables;
\r
35 TObjectIntHashMap<Variable> variableMap;
\r
36 ArrayList<ArrayList<PrePlanItem>> itemsContainingVariable;
\r
37 ArrayList<PlanOp> planOps = new ArrayList<PlanOp>();
\r
39 public QueryPlanningContext(CompilationContext compilationContext, Variable[] variables) {
\r
40 this.compilationContext = compilationContext;
\r
41 this.variables = new ArrayList<Variable>(variables.length*2);
\r
42 this.variableMap = new TObjectIntHashMap<Variable>(variables.length, Constants.DEFAULT_LOAD_FACTOR, -1);
\r
43 itemsContainingVariable = new ArrayList<ArrayList<PrePlanItem>>(variables.length*2);
\r
44 for(Variable variable : variables)
\r
45 addVariable(variable);
\r
48 private void addVariable(Variable variable) {
\r
49 int id = variables.size();
\r
50 variables.add(variable);
\r
51 variableMap.put(variable, id);
\r
52 itemsContainingVariable.add(new ArrayList<PrePlanItem>(2));
\r
55 public void add(CHRLiteral literal, int secondaryPriority) {
\r
56 if(literal.relation instanceof SpecialCHRRelation) {
\r
57 switch((SpecialCHRRelation)literal.relation) {
\r
59 addCheck(literal.location, literal.parameters[0], secondaryPriority);
\r
62 addGenericEquals(literal.location, literal.parameters[0], literal.parameters[1], secondaryPriority);
\r
65 addMember(literal.location, literal.parameters[0], literal.parameters[1], secondaryPriority);
\r
68 throw new InternalCompilerError(literal.location, "EXECUTE constraint is not allowed in query compilation.");
\r
72 addGenericConstraint(literal, secondaryPriority);
\r
75 private TIntHashSet getVars(Expression expression, int initialCapacity) {
\r
76 TIntHashSet variableSet = new TIntHashSet(initialCapacity);
\r
77 expression.collectVars(variableMap, variableSet);
\r
81 private TIntHashSet[] getVars(Expression[] expressions, int initialCapacity) {
\r
82 TIntHashSet[] variableSets = new TIntHashSet[expressions.length];
\r
83 for(int i=0;i<expressions.length;++i)
\r
84 variableSets[i] = getVars(expressions[i], initialCapacity);
\r
85 return variableSets;
\r
89 * Returns true, if the expression is so simple, it does not involve any computation.
\r
91 private static boolean isSimpleExpression(Expression expression) {
\r
92 while(expression instanceof EApplyType)
\r
93 expression = ((EApplyType)expression).getExpression();
\r
94 return expression instanceof EVariable
\r
95 || expression instanceof EConstant
\r
96 || expression instanceof ELiteral
\r
97 || expression instanceof EExternalConstant;
\r
100 private Expression toSimpleExpression(Expression expression, int secondaryPriority) {
\r
101 if(isSimpleExpression(expression))
\r
104 Variable temp = new Variable("temp", expression.getType());
\r
106 addOneSidedEquals(expression.location, new EVariable(temp), expression, secondaryPriority);
\r
107 return new EVariable(temp);
\r
111 private Expression[] toSimpleExpressions(Expression[] expressions, int secondaryPriority) {
\r
112 Expression[] result = new Expression[expressions.length];
\r
113 for(int i=0;i<expressions.length;++i)
\r
114 result[i] = toSimpleExpression(expressions[i], secondaryPriority);
\r
118 private void addGenericConstraint(CHRLiteral literal, int secondaryPriority) {
\r
119 if(literal.killAfterMatch)
\r
120 ((CHRConstraint)literal.relation).setMayBeRemoved();
\r
121 Expression[] parameters = toSimpleExpressions(literal.parameters, secondaryPriority);
\r
122 add(literal.location, new GenericPrePlanItem(literal, literal.relation, parameters, getVars(parameters, 1), secondaryPriority));
\r
125 private void addMember(long location, Expression p1, Expression p2, int secondaryPriority) {
\r
126 Expression expression1 = toSimpleExpression(p1, secondaryPriority);
\r
127 Expression expression2 = toSimpleExpression(p2, secondaryPriority);
\r
128 add(location, new MemberPrePlanItem(expression1, expression2,
\r
129 getVars(expression1, 1), getVars(expression2, 1), secondaryPriority));
\r
132 private void addOneSidedEquals(long location, Expression expression1, Expression expression2, int secondaryPriority) {
\r
133 add(location, new EqualsPrePlanItem(expression1, expression2,
\r
134 getVars(expression1, 1), getVars(expression2, 4), secondaryPriority));
\r
137 private void addGenericEquals(long location, Expression p1, Expression p2, int secondaryPriority) {
\r
138 if(isSimpleExpression(p1))
\r
139 addOneSidedEquals(location, p1, p2, secondaryPriority);
\r
140 else if(isSimpleExpression(p2))
\r
141 addOneSidedEquals(location, p2, p1, secondaryPriority);
\r
143 Variable temp = new Variable("temp", p1.getType());
\r
145 addOneSidedEquals(p1.location, new EVariable(temp), p1, secondaryPriority);
\r
146 addOneSidedEquals(p2.location, new EVariable(temp), p2, secondaryPriority);
\r
150 private void addCheck(long location, Expression condition, int secondaryPriority) {
\r
151 TIntHashSet variableSet = new TIntHashSet(4);
\r
152 condition.collectVars(variableMap, variableSet);
\r
153 add(location, new CheckPrePlanItem(condition, variableSet, secondaryPriority));
\r
156 private void add(long location, PrePlanItem item) {
\r
157 priorityQueue.add(item);
\r
158 item.initializeListeners(this);
\r
159 item.location = location;
\r
162 public void listen(TIntHashSet variableSet, PrePlanItem item) {
\r
163 variableSet.forEach(new TIntProcedure() {
\r
165 public boolean execute(int variableId) {
\r
166 listen(variableId, item);
\r
172 public void listen(int variableId, PrePlanItem item) {
\r
173 itemsContainingVariable.get(variableId).add(item);
\r
176 public void createQueryPlan() {
\r
177 while(!priorityQueue.isEmpty()) {
\r
178 PrePlanItem head = priorityQueue.head();
\r
179 priorityQueue.pop();
\r
180 head.generate(this);
\r
184 public ArrayList<PlanOp> getPlanOps() {
\r
188 private final TIntProcedure BIND_PROCEDURE = new TIntProcedure() {
\r
190 public boolean execute(int variableId) {
\r
191 ArrayList<PrePlanItem> l = itemsContainingVariable.get(variableId);
\r
192 for(PrePlanItem item : l)
\r
193 item.variableSolved(QueryPlanningContext.this, variableId);
\r
199 public void bind(TIntHashSet variableSet) {
\r
200 variableSet.forEach(BIND_PROCEDURE);
\r
203 public void addPlanOp(PlanOp planOp) {
\r
204 planOps.add(planOp);
\r
207 public CompilationContext getCompilationContext() {
\r
208 return compilationContext;
\r
211 public void activate(CHRLiteral literal, Expression inputFact, int secondaryPriority) {
\r
212 Variable[] variables = new Variable[literal.parameters.length];
\r
213 for(int i=0;i<literal.parameters.length;++i)
\r
214 variables[i] = new Variable("activeFactComponent" + i, literal.parameters[i].getType());
\r
215 if(literal.killAfterMatch)
\r
216 ((CHRConstraint)literal.relation).setMayBeRemoved();
\r
217 planOps.add(new AccessFactOp(literal.location, inputFact, (CHRConstraint)literal.relation, variables, literal.killAfterMatch));
\r
218 for(int i=0;i<literal.parameters.length;++i)
\r
219 addOneSidedEquals(literal.parameters[i].location, new EVariable(variables[i]), literal.parameters[i], secondaryPriority);
\r
222 public void claim(QueryPlanningContext context, CHRLiteral literal) {
\r
223 if(literal.relation instanceof CHRConstraint) {
\r
224 CHRConstraint constraint = (CHRConstraint)literal.relation;
\r
225 addPlanOp(new ClaimOp(literal.location, constraint, literal.parameters));
\r
227 else if(literal.relation instanceof SpecialCHRRelation) {
\r
228 switch((SpecialCHRRelation)literal.relation) {
\r
230 addPlanOp(new ExecuteOp(literal.location, literal.parameters[0]));
\r
233 context.getCompilationContext().errorLog.log(
\r
235 "Cannot enforce this constraint.");
\r