--- /dev/null
+package org.simantics.scl.compiler.elaboration.chr.planning;\r
+\r
+import java.util.ArrayList;\r
+\r
+import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;\r
+import org.simantics.scl.compiler.compilation.CompilationContext;\r
+import org.simantics.scl.compiler.elaboration.chr.CHRLiteral;\r
+import org.simantics.scl.compiler.elaboration.chr.plan.AccessFactOp;\r
+import org.simantics.scl.compiler.elaboration.chr.plan.ClaimOp;\r
+import org.simantics.scl.compiler.elaboration.chr.plan.ExecuteOp;\r
+import org.simantics.scl.compiler.elaboration.chr.plan.PlanOp;\r
+import org.simantics.scl.compiler.elaboration.chr.planning.items.CheckPrePlanItem;\r
+import org.simantics.scl.compiler.elaboration.chr.planning.items.EqualsPrePlanItem;\r
+import org.simantics.scl.compiler.elaboration.chr.planning.items.GenericPrePlanItem;\r
+import org.simantics.scl.compiler.elaboration.chr.planning.items.MemberPrePlanItem;\r
+import org.simantics.scl.compiler.elaboration.chr.relations.CHRConstraint;\r
+import org.simantics.scl.compiler.elaboration.chr.relations.SpecialCHRRelation;\r
+import org.simantics.scl.compiler.elaboration.expressions.EApplyType;\r
+import org.simantics.scl.compiler.elaboration.expressions.EConstant;\r
+import org.simantics.scl.compiler.elaboration.expressions.EExternalConstant;\r
+import org.simantics.scl.compiler.elaboration.expressions.ELiteral;\r
+import org.simantics.scl.compiler.elaboration.expressions.EVariable;\r
+import org.simantics.scl.compiler.elaboration.expressions.Expression;\r
+import org.simantics.scl.compiler.elaboration.expressions.Variable;\r
+\r
+import gnu.trove.impl.Constants;\r
+import gnu.trove.map.hash.TObjectIntHashMap;\r
+import gnu.trove.procedure.TIntProcedure;\r
+import gnu.trove.set.hash.TIntHashSet;\r
+\r
+public class QueryPlanningContext {\r
+ CompilationContext compilationContext;\r
+ public PlanPriorityQueue priorityQueue = new PlanPriorityQueue();\r
+ ArrayList<Variable> variables;\r
+ TObjectIntHashMap<Variable> variableMap;\r
+ ArrayList<ArrayList<PrePlanItem>> itemsContainingVariable;\r
+ ArrayList<PlanOp> planOps = new ArrayList<PlanOp>(); \r
+ \r
+ public QueryPlanningContext(CompilationContext compilationContext, Variable[] variables) {\r
+ this.compilationContext = compilationContext;\r
+ this.variables = new ArrayList<Variable>(variables.length*2);\r
+ this.variableMap = new TObjectIntHashMap<Variable>(variables.length, Constants.DEFAULT_LOAD_FACTOR, -1);\r
+ itemsContainingVariable = new ArrayList<ArrayList<PrePlanItem>>(variables.length*2);\r
+ for(Variable variable : variables)\r
+ addVariable(variable);\r
+ }\r
+ \r
+ private void addVariable(Variable variable) {\r
+ int id = variables.size();\r
+ variables.add(variable);\r
+ variableMap.put(variable, id);\r
+ itemsContainingVariable.add(new ArrayList<PrePlanItem>(2));\r
+ }\r
+\r
+ public void add(CHRLiteral literal, int secondaryPriority) {\r
+ if(literal.relation instanceof SpecialCHRRelation) {\r
+ switch((SpecialCHRRelation)literal.relation) {\r
+ case CHECK:\r
+ addCheck(literal.location, literal.parameters[0], secondaryPriority);\r
+ return;\r
+ case EQUALS:\r
+ addGenericEquals(literal.location, literal.parameters[0], literal.parameters[1], secondaryPriority);\r
+ return;\r
+ case MEMBER:\r
+ addMember(literal.location, literal.parameters[0], literal.parameters[1], secondaryPriority);\r
+ return;\r
+ case EXECUTE:\r
+ throw new InternalCompilerError(literal.location, "EXECUTE constraint is not allowed in query compilation.");\r
+ }\r
+ }\r
+ \r
+ addGenericConstraint(literal, secondaryPriority);\r
+ }\r
+ \r
+ private TIntHashSet getVars(Expression expression, int initialCapacity) {\r
+ TIntHashSet variableSet = new TIntHashSet(initialCapacity);\r
+ expression.collectVars(variableMap, variableSet);\r
+ return variableSet;\r
+ }\r
+ \r
+ private TIntHashSet[] getVars(Expression[] expressions, int initialCapacity) {\r
+ TIntHashSet[] variableSets = new TIntHashSet[expressions.length];\r
+ for(int i=0;i<expressions.length;++i)\r
+ variableSets[i] = getVars(expressions[i], initialCapacity);\r
+ return variableSets;\r
+ }\r
+ \r
+ /**\r
+ * Returns true, if the expression is so simple, it does not involve any computation.\r
+ */\r
+ private static boolean isSimpleExpression(Expression expression) {\r
+ while(expression instanceof EApplyType)\r
+ expression = ((EApplyType)expression).getExpression();\r
+ return expression instanceof EVariable \r
+ || expression instanceof EConstant\r
+ || expression instanceof ELiteral\r
+ || expression instanceof EExternalConstant;\r
+ }\r
+ \r
+ private Expression toSimpleExpression(Expression expression, int secondaryPriority) {\r
+ if(isSimpleExpression(expression)) \r
+ return expression;\r
+ else {\r
+ Variable temp = new Variable("temp", expression.getType());\r
+ addVariable(temp);\r
+ addOneSidedEquals(expression.location, new EVariable(temp), expression, secondaryPriority);\r
+ return new EVariable(temp);\r
+ }\r
+ }\r
+ \r
+ private Expression[] toSimpleExpressions(Expression[] expressions, int secondaryPriority) {\r
+ Expression[] result = new Expression[expressions.length];\r
+ for(int i=0;i<expressions.length;++i)\r
+ result[i] = toSimpleExpression(expressions[i], secondaryPriority);\r
+ return result;\r
+ }\r
+\r
+ private void addGenericConstraint(CHRLiteral literal, int secondaryPriority) {\r
+ if(literal.killAfterMatch)\r
+ ((CHRConstraint)literal.relation).setMayBeRemoved();\r
+ Expression[] parameters = toSimpleExpressions(literal.parameters, secondaryPriority);\r
+ add(literal.location, new GenericPrePlanItem(literal, literal.relation, parameters, getVars(parameters, 1), secondaryPriority));\r
+ }\r
+\r
+ private void addMember(long location, Expression p1, Expression p2, int secondaryPriority) {\r
+ Expression expression1 = toSimpleExpression(p1, secondaryPriority);\r
+ Expression expression2 = toSimpleExpression(p2, secondaryPriority);\r
+ add(location, new MemberPrePlanItem(expression1, expression2,\r
+ getVars(expression1, 1), getVars(expression2, 1), secondaryPriority));\r
+ }\r
+ \r
+ private void addOneSidedEquals(long location, Expression expression1, Expression expression2, int secondaryPriority) {\r
+ add(location, new EqualsPrePlanItem(expression1, expression2,\r
+ getVars(expression1, 1), getVars(expression2, 4), secondaryPriority));\r
+ }\r
+\r
+ private void addGenericEquals(long location, Expression p1, Expression p2, int secondaryPriority) {\r
+ if(isSimpleExpression(p1))\r
+ addOneSidedEquals(location, p1, p2, secondaryPriority);\r
+ else if(isSimpleExpression(p2))\r
+ addOneSidedEquals(location, p2, p1, secondaryPriority);\r
+ else {\r
+ Variable temp = new Variable("temp", p1.getType());\r
+ addVariable(temp);\r
+ addOneSidedEquals(p1.location, new EVariable(temp), p1, secondaryPriority);\r
+ addOneSidedEquals(p2.location, new EVariable(temp), p2, secondaryPriority);\r
+ }\r
+ }\r
+\r
+ private void addCheck(long location, Expression condition, int secondaryPriority) {\r
+ TIntHashSet variableSet = new TIntHashSet(4);\r
+ condition.collectVars(variableMap, variableSet);\r
+ add(location, new CheckPrePlanItem(condition, variableSet, secondaryPriority));\r
+ }\r
+\r
+ private void add(long location, PrePlanItem item) {\r
+ priorityQueue.add(item);\r
+ item.initializeListeners(this);\r
+ item.location = location;\r
+ }\r
+\r
+ public void listen(TIntHashSet variableSet, PrePlanItem item) {\r
+ variableSet.forEach(new TIntProcedure() {\r
+ @Override\r
+ public boolean execute(int variableId) {\r
+ listen(variableId, item);\r
+ return true;\r
+ }\r
+ });\r
+ }\r
+\r
+ public void listen(int variableId, PrePlanItem item) {\r
+ itemsContainingVariable.get(variableId).add(item);\r
+ }\r
+\r
+ public void createQueryPlan() {\r
+ while(!priorityQueue.isEmpty()) {\r
+ PrePlanItem head = priorityQueue.head();\r
+ priorityQueue.pop();\r
+ head.generate(this);\r
+ }\r
+ }\r
+ \r
+ public ArrayList<PlanOp> getPlanOps() {\r
+ return planOps;\r
+ }\r
+ \r
+ private final TIntProcedure BIND_PROCEDURE = new TIntProcedure() {\r
+ @Override\r
+ public boolean execute(int variableId) {\r
+ ArrayList<PrePlanItem> l = itemsContainingVariable.get(variableId);\r
+ for(PrePlanItem item : l)\r
+ item.variableSolved(QueryPlanningContext.this, variableId);\r
+ l.clear();\r
+ return true;\r
+ }\r
+ };\r
+\r
+ public void bind(TIntHashSet variableSet) {\r
+ variableSet.forEach(BIND_PROCEDURE);\r
+ }\r
+\r
+ public void addPlanOp(PlanOp planOp) {\r
+ planOps.add(planOp);\r
+ }\r
+\r
+ public CompilationContext getCompilationContext() {\r
+ return compilationContext;\r
+ }\r
+\r
+ public void activate(CHRLiteral literal, Expression inputFact, int secondaryPriority) {\r
+ Variable[] variables = new Variable[literal.parameters.length];\r
+ for(int i=0;i<literal.parameters.length;++i)\r
+ variables[i] = new Variable("activeFactComponent" + i, literal.parameters[i].getType());\r
+ if(literal.killAfterMatch)\r
+ ((CHRConstraint)literal.relation).setMayBeRemoved();\r
+ planOps.add(new AccessFactOp(literal.location, inputFact, (CHRConstraint)literal.relation, variables, literal.killAfterMatch));\r
+ for(int i=0;i<literal.parameters.length;++i)\r
+ addOneSidedEquals(literal.parameters[i].location, new EVariable(variables[i]), literal.parameters[i], secondaryPriority);\r
+ }\r
+\r
+ public void claim(QueryPlanningContext context, CHRLiteral literal) {\r
+ if(literal.relation instanceof CHRConstraint) {\r
+ CHRConstraint constraint = (CHRConstraint)literal.relation;\r
+ addPlanOp(new ClaimOp(literal.location, constraint, literal.parameters));\r
+ }\r
+ else if(literal.relation instanceof SpecialCHRRelation) {\r
+ switch((SpecialCHRRelation)literal.relation) {\r
+ case EXECUTE:\r
+ addPlanOp(new ExecuteOp(literal.location, literal.parameters[0]));\r
+ break;\r
+ default:\r
+ context.getCompilationContext().errorLog.log(\r
+ literal.location,\r
+ "Cannot enforce this constraint.");\r
+ }\r
+ }\r
+ }\r
+\r
+}\r