]> gerrit.simantics Code Review - simantics/platform.git/blob
c083b8fc9693a41b25ba3165bb2df6f5096c65ea
[simantics/platform.git] /
1 package org.simantics.scl.compiler.elaboration.chr.planning;\r
2 \r
3 import java.util.ArrayList;\r
4 \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
25 \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
30 \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
38     \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
46     }\r
47     \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
53     }\r
54 \r
55     public void add(CHRLiteral literal, int secondaryPriority) {\r
56         if(literal.relation instanceof SpecialCHRRelation) {\r
57             switch((SpecialCHRRelation)literal.relation) {\r
58             case CHECK:\r
59                 addCheck(literal.location, literal.parameters[0], secondaryPriority);\r
60                 return;\r
61             case EQUALS:\r
62                 addGenericEquals(literal.location, literal.parameters[0], literal.parameters[1], secondaryPriority);\r
63                 return;\r
64             case MEMBER:\r
65                 addMember(literal.location, literal.parameters[0], literal.parameters[1], secondaryPriority);\r
66                 return;\r
67             case EXECUTE:\r
68                 throw new InternalCompilerError(literal.location, "EXECUTE constraint is not allowed in query compilation.");\r
69             }\r
70         }\r
71         \r
72         addGenericConstraint(literal, secondaryPriority);\r
73     }\r
74     \r
75     private TIntHashSet getVars(Expression expression, int initialCapacity) {\r
76         TIntHashSet variableSet = new TIntHashSet(initialCapacity);\r
77         expression.collectVars(variableMap, variableSet);\r
78         return variableSet;\r
79     }\r
80     \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
86     }\r
87     \r
88     /**\r
89      * Returns true, if the expression is so simple, it does not involve any computation.\r
90      */\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
98     }\r
99     \r
100     private Expression toSimpleExpression(Expression expression, int secondaryPriority) {\r
101         if(isSimpleExpression(expression))        \r
102             return expression;\r
103         else {\r
104             Variable temp = new Variable("temp", expression.getType());\r
105             addVariable(temp);\r
106             addOneSidedEquals(expression.location, new EVariable(temp), expression, secondaryPriority);\r
107             return new EVariable(temp);\r
108         }\r
109     }\r
110     \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
115         return result;\r
116     }\r
117 \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
123     }\r
124 \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
130     }\r
131     \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
135     }\r
136 \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
142         else {\r
143             Variable temp = new Variable("temp", p1.getType());\r
144             addVariable(temp);\r
145             addOneSidedEquals(p1.location, new EVariable(temp), p1, secondaryPriority);\r
146             addOneSidedEquals(p2.location, new EVariable(temp), p2, secondaryPriority);\r
147         }\r
148     }\r
149 \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
154     }\r
155 \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
160     }\r
161 \r
162     public void listen(TIntHashSet variableSet, PrePlanItem item) {\r
163         variableSet.forEach(new TIntProcedure() {\r
164             @Override\r
165             public boolean execute(int variableId) {\r
166                 listen(variableId, item);\r
167                 return true;\r
168             }\r
169         });\r
170     }\r
171 \r
172     public void listen(int variableId, PrePlanItem item) {\r
173         itemsContainingVariable.get(variableId).add(item);\r
174     }\r
175 \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
181         }\r
182     }\r
183     \r
184     public ArrayList<PlanOp> getPlanOps() {\r
185         return planOps;\r
186     }\r
187     \r
188     private final TIntProcedure BIND_PROCEDURE = new TIntProcedure() {\r
189         @Override\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
194             l.clear();\r
195             return true;\r
196         }\r
197     };\r
198 \r
199     public void bind(TIntHashSet variableSet) {\r
200         variableSet.forEach(BIND_PROCEDURE);\r
201     }\r
202 \r
203     public void addPlanOp(PlanOp planOp) {\r
204         planOps.add(planOp);\r
205     }\r
206 \r
207     public CompilationContext getCompilationContext() {\r
208         return compilationContext;\r
209     }\r
210 \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
220     }\r
221 \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
226         }\r
227         else if(literal.relation instanceof SpecialCHRRelation) {\r
228             switch((SpecialCHRRelation)literal.relation) {\r
229             case EXECUTE:\r
230                 addPlanOp(new ExecuteOp(literal.location, literal.parameters[0]));\r
231                 break;\r
232             default:\r
233                 context.getCompilationContext().errorLog.log(\r
234                         literal.location,\r
235                         "Cannot enforce this constraint.");\r
236             }\r
237         }\r
238     }\r
239 \r
240 }\r