1 package org.simantics.scl.compiler.elaboration.chr.planning;
3 import java.util.ArrayList;
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;
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;
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>();
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);
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));
57 public void add(CHRLiteral literal, int secondaryPriority) {
58 if(literal.relation instanceof SpecialCHRRelation) {
59 switch((SpecialCHRRelation)literal.relation) {
61 addCheck(literal.location, literal.parameters[0], secondaryPriority);
64 addGenericEquals(literal.location, literal.parameters[0], literal.parameters[1], secondaryPriority);
67 addMember(literal.location, literal.parameters[0], literal.parameters[1], secondaryPriority);
70 throw new InternalCompilerError(literal.location, "ASSIGN constraint is not allowed in query compilation.");
72 throw new InternalCompilerError(literal.location, "EXECUTE constraint is not allowed in query compilation.");
76 addGenericConstraint(literal, secondaryPriority);
79 private TIntHashSet getVars(Expression expression, int initialCapacity) {
80 TIntHashSet variableSet = new TIntHashSet(initialCapacity);
81 expression.collectVars(variableMap, variableSet);
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);
93 * Returns true, if the expression is so simple, it does not involve any computation.
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;
104 private Expression toSimpleExpression(Expression expression, int secondaryPriority) {
105 if(isSimpleExpression(expression))
108 Variable temp = new Variable("temp", expression.getType());
110 addOneSidedEquals(expression.location, new EVariable(temp), expression, secondaryPriority);
111 return new EVariable(temp);
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);
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));
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));
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));
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);
147 Variable temp = new Variable("temp", p1.getType());
149 addOneSidedEquals(p1.location, new EVariable(temp), p1, secondaryPriority);
150 addOneSidedEquals(p2.location, new EVariable(temp), p2, secondaryPriority);
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));
160 private void add(long location, PrePlanItem item) {
161 priorityQueue.add(item);
162 item.initializeListeners(this);
163 item.location = location;
166 public void listen(TIntHashSet variableSet, PrePlanItem item) {
167 variableSet.forEach(new TIntProcedure() {
169 public boolean execute(int variableId) {
170 listen(variableId, item);
176 public void listen(int variableId, PrePlanItem item) {
177 itemsContainingVariable.get(variableId).add(item);
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.");
193 public ArrayList<PlanOp> getPlanOps() {
197 private final TIntProcedure BIND_PROCEDURE = new TIntProcedure() {
199 public boolean execute(int variableId) {
200 ArrayList<PrePlanItem> l = itemsContainingVariable.get(variableId);
201 for(PrePlanItem item : l)
202 item.variableSolved(QueryPlanningContext.this, variableId);
208 public void bind(TIntHashSet variableSet) {
209 variableSet.forEach(BIND_PROCEDURE);
212 public void addPlanOp(PlanOp planOp) {
216 public CompilationContext getCompilationContext() {
217 return compilationContext;
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);
231 public void addInitFact(CHRConstraint initConstraint, Expression inputFact) {
232 planOps.add(new AccessFactOp(Locations.NO_LOCATION, inputFact, initConstraint, Variable.EMPTY_ARRAY, false));
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));
240 else if(literal.relation instanceof SpecialCHRRelation) {
241 switch((SpecialCHRRelation)literal.relation) {
243 addPlanOp(new ExecuteOp(literal.location, literal.parameters[0]));
246 addPlanOp(new MatchOp(literal.location, literal.parameters[1], literal.parameters[0]));
249 context.getCompilationContext().errorLog.log(
251 "Cannot enforce this constraint.");