1 | package de.uka.ipd.sdq.simucomframework.variables.stoexvisitor; |
2 | |
3 | import java.util.ArrayList; |
4 | import java.util.Map.Entry; |
5 | |
6 | import org.apache.log4j.Logger; |
7 | |
8 | import de.uka.ipd.sdq.pcm.parameter.CharacterisedVariable; |
9 | import de.uka.ipd.sdq.pcm.stochasticexpressions.PCMStoExPrettyPrintVisitor; |
10 | import de.uka.ipd.sdq.pcm.stochasticexpressions.PCMStoExSwitch; |
11 | |
12 | import de.uka.ipd.sdq.probfunction.math.IProbabilityFunctionFactory; |
13 | |
14 | import de.uka.ipd.sdq.simucomframework.variables.EvaluationProxy; |
15 | import de.uka.ipd.sdq.simucomframework.variables.StackContext; |
16 | |
17 | import de.uka.ipd.sdq.simucomframework.variables.cache.StoExCacheEntry; |
18 | import de.uka.ipd.sdq.simucomframework.variables.exceptions.TypesIncompatibleInComparisionException; |
19 | import de.uka.ipd.sdq.simucomframework.variables.exceptions.TypesIncompatibleInProductException; |
20 | import de.uka.ipd.sdq.simucomframework.variables.exceptions.TypesIncompatibleInTermException; |
21 | import de.uka.ipd.sdq.simucomframework.variables.exceptions.ValueNotInFrameException; |
22 | import de.uka.ipd.sdq.simucomframework.variables.functions.FunctionLib; |
23 | import de.uka.ipd.sdq.simucomframework.variables.stackframe.SimulatedStackframe; |
24 | import de.uka.ipd.sdq.stoex.BoolLiteral; |
25 | import de.uka.ipd.sdq.stoex.BooleanOperatorExpression; |
26 | import de.uka.ipd.sdq.stoex.CompareExpression; |
27 | import de.uka.ipd.sdq.stoex.DoubleLiteral; |
28 | import de.uka.ipd.sdq.stoex.Expression; |
29 | import de.uka.ipd.sdq.stoex.FunctionLiteral; |
30 | import de.uka.ipd.sdq.stoex.IfElseExpression; |
31 | import de.uka.ipd.sdq.stoex.IntLiteral; |
32 | import de.uka.ipd.sdq.stoex.NegativeExpression; |
33 | import de.uka.ipd.sdq.stoex.NotExpression; |
34 | import de.uka.ipd.sdq.stoex.Parenthesis; |
35 | import de.uka.ipd.sdq.stoex.PowerExpression; |
36 | import de.uka.ipd.sdq.stoex.ProbabilityFunctionLiteral; |
37 | import de.uka.ipd.sdq.stoex.ProductExpression; |
38 | import de.uka.ipd.sdq.stoex.StringLiteral; |
39 | import de.uka.ipd.sdq.stoex.TermExpression; |
40 | import de.uka.ipd.sdq.stoex.analyser.visitors.ExpressionInferTypeVisitor; |
41 | import de.uka.ipd.sdq.stoex.analyser.visitors.TypeEnum; |
42 | |
43 | |
44 | /** |
45 | * Visitor to evaluate stoex. It executes the corresponding Java mathematical |
46 | * operations at each operator. It partially relies on the types infered |
47 | * to do its casts |
48 | * @author Steffen Becker |
49 | * |
50 | */ |
51 | public class PCMStoExEvaluationVisitor extends PCMStoExSwitch { |
52 | |
53 | /** |
54 | * This class' logger |
55 | */ |
56 | private static final Logger logger = |
57 | Logger.getLogger(PCMStoExEvaluationVisitor.class.getName()); |
58 | |
59 | /** |
60 | * Pretty printer. This class is stateless hence it is save to have just one object of it |
61 | */ |
62 | private final static PCMStoExPrettyPrintVisitor printVisitor = new PCMStoExPrettyPrintVisitor(); |
63 | |
64 | /** |
65 | * Subvisitor to evaluate probability functions inside the visited stoex |
66 | */ |
67 | private final PCMProbfunctionEvaluationVisitor probfunctionVisitor; |
68 | |
69 | /** |
70 | * Stackframe against which variables will be evaluated |
71 | */ |
72 | private final SimulatedStackframe<Object> myStackFrame; |
73 | |
74 | /** |
75 | * Type infer visitor which will be used to infer the stoex's type |
76 | */ |
77 | private final ExpressionInferTypeVisitor typeInferer; |
78 | |
79 | /** |
80 | * Function lib contains functions like Exp, etc. This cannot be static as it depends on its respective |
81 | * random number generator |
82 | */ |
83 | private final FunctionLib functionLib; |
84 | |
85 | /** |
86 | * Mode for evaluating variables. Determines when to throw Exceptions if some evaluation fails |
87 | */ |
88 | private VariableMode mode; |
89 | |
90 | public PCMStoExEvaluationVisitor(StoExCacheEntry cacheEntry, SimulatedStackframe<Object> frame, VariableMode initialMode, IProbabilityFunctionFactory probFunctionFactory) { |
91 | this.typeInferer = cacheEntry.getTypeInferer(); |
92 | myStackFrame = frame; |
93 | this.mode = initialMode; |
94 | probfunctionVisitor = new PCMProbfunctionEvaluationVisitor(cacheEntry); |
95 | functionLib = new FunctionLib(probFunctionFactory.getRandomGenerator(), probFunctionFactory.getPDFFactory()); |
96 | } |
97 | |
98 | public void setVariableMode(VariableMode mode) { |
99 | this.mode = mode; |
100 | } |
101 | |
102 | public VariableMode getVariableMode() { |
103 | return this.mode; |
104 | } |
105 | |
106 | @Override |
107 | public Object caseCharacterisedVariable(CharacterisedVariable object) { |
108 | String variableID = (String)printVisitor.caseCharacterisedVariable(object); |
109 | try { |
110 | Object value = this.myStackFrame.getValue(variableID); |
111 | if (value instanceof EvaluationProxy) { |
112 | EvaluationProxy proxy = (EvaluationProxy)value; |
113 | return StackContext.evaluateStatic(proxy.getStoEx(), proxy.getStackFrame()); |
114 | } else { |
115 | return value; |
116 | } |
117 | } catch (ValueNotInFrameException e) { |
118 | if (mode == VariableMode.EXCEPTION_ON_NOT_FOUND) { |
119 | logger.error("Value should be in stackframe, but it is not!",e); |
120 | e.printStackTrace(); |
121 | } |
122 | } |
123 | if (mode == VariableMode.EXCEPTION_ON_NOT_FOUND) { |
124 | String availableIDs = ""; |
125 | for (Entry<String, Object> e : this.myStackFrame.getContents()) { |
126 | availableIDs += "<"+e.getKey()+"> "; |
127 | } |
128 | RuntimeException re = new RuntimeException("Architecture specification incomplete. Stackframe is missing id "+variableID+"\nAvailable IDs are "+availableIDs); |
129 | logger.error("Value not found in specification",re); |
130 | throw re; |
131 | } else if (mode == VariableMode.RETURN_NULL_ON_NOT_FOUND) { |
132 | return null; |
133 | } else { |
134 | if (typeInferer.getType(object) == TypeEnum.INT) |
135 | return 0; |
136 | if (typeInferer.getType(object) == TypeEnum.DOUBLE) |
137 | return 0.0; |
138 | if (typeInferer.getType(object) == TypeEnum.ENUM) |
139 | return ""; |
140 | if (typeInferer.getType(object) == TypeEnum.BOOL) |
141 | return false; |
142 | RuntimeException re = new RuntimeException("Architecture specification incomplete. Stackframe is missing id "+variableID); |
143 | logger.error("Value not found in specification",re); |
144 | throw re; |
145 | } |
146 | } |
147 | |
148 | @SuppressWarnings("unchecked") |
149 | @Override |
150 | public Object caseCompareExpression(CompareExpression object) { |
151 | TypeEnum leftType = typeInferer.getType(object.getLeft()); |
152 | TypeEnum rightType = typeInferer.getType(object.getRight()); |
153 | Object leftExpr = doSwitch(object.getLeft()); |
154 | Object rightExpr = doSwitch(object.getRight()); |
155 | if (leftType == TypeEnum.ANY) leftType = getDynamicType(leftExpr); |
156 | if (rightType == TypeEnum.ANY) rightType = getDynamicType(rightExpr); |
157 | |
158 | if (leftType == TypeEnum.INT && rightType == TypeEnum.DOUBLE) |
159 | leftExpr = Double.valueOf( (((Integer)leftExpr).intValue())); |
160 | if (rightType == TypeEnum.INT && leftType == TypeEnum.DOUBLE) |
161 | rightExpr = Double.valueOf( (((Integer)rightExpr).intValue())); |
162 | |
163 | // If types still don't comply, give up! |
164 | if (leftExpr.getClass() != rightExpr.getClass()) { |
165 | throw new TypesIncompatibleInComparisionException("Can not compare "+leftExpr.getClass().getName()+" to "+rightExpr.getClass().getName()); |
166 | } |
167 | |
168 | int result = ((Comparable)leftExpr).compareTo(rightExpr); |
169 | switch(object.getOperation()) |
170 | { |
171 | case EQUALS: |
172 | return result == 0; |
173 | case LESS: |
174 | return result < 0; |
175 | case LESSEQUAL: |
176 | return result <= 0; |
177 | case GREATER: |
178 | return result > 0; |
179 | case GREATEREQUAL: |
180 | return result >= 0; |
181 | case NOTEQUAL: |
182 | return result != 0; |
183 | } |
184 | throw new RuntimeException("Unknown Compare Operation found! Should not happen!"); |
185 | } |
186 | |
187 | @Override |
188 | public Object caseDoubleLiteral(DoubleLiteral object) { |
189 | return object.getValue(); |
190 | } |
191 | |
192 | @Override |
193 | public Object caseIntLiteral(IntLiteral object) { |
194 | return object.getValue(); |
195 | } |
196 | |
197 | @Override |
198 | public Object caseStringLiteral(StringLiteral object) { |
199 | return object.getValue(); |
200 | } |
201 | |
202 | @Override |
203 | public Object caseParenthesis(Parenthesis object) { |
204 | return doSwitch(object.getInnerExpression()); |
205 | } |
206 | |
207 | @Override |
208 | public Object caseProbabilityFunctionLiteral(ProbabilityFunctionLiteral object) { |
209 | return probfunctionVisitor.doSwitch(object.getFunction_ProbabilityFunctionLiteral()); |
210 | } |
211 | |
212 | @Override |
213 | public Object caseProductExpression(ProductExpression object) { |
214 | TypeEnum leftType = typeInferer.getType(object.getLeft()); |
215 | TypeEnum rightType = typeInferer.getType(object.getRight()); |
216 | Object left = doSwitch(object.getLeft()); |
217 | Object right = doSwitch(object.getRight()); |
218 | if (leftType == TypeEnum.ANY) leftType = getDynamicType(left); |
219 | if (rightType == TypeEnum.ANY) rightType = getDynamicType(right); |
220 | if (leftType == TypeEnum.INT && rightType == TypeEnum.INT) { |
221 | if (!(left instanceof Integer) || !(right instanceof Integer)) { |
222 | throw new TypesIncompatibleInProductException("Incompatible types in product expression. Expecting Integer!"); |
223 | } |
224 | |
225 | int leftInt = (Integer)left; |
226 | int rightInt = (Integer)right; |
227 | switch(object.getOperation()) |
228 | { |
229 | case DIV: |
230 | return leftInt / rightInt; |
231 | case MULT: |
232 | return leftInt * rightInt; |
233 | case MOD: |
234 | return leftInt % rightInt; |
235 | } |
236 | throw new RuntimeException("This should never happen!"); |
237 | |
238 | } else { |
239 | double leftDouble = getDouble(left); |
240 | double rightDouble = getDouble(right); |
241 | switch(object.getOperation()) |
242 | { |
243 | case DIV: |
244 | return leftDouble / rightDouble; |
245 | case MULT: |
246 | return leftDouble * rightDouble; |
247 | case MOD: |
248 | return leftDouble % rightDouble; |
249 | } |
250 | throw new RuntimeException("This should never happen!"); |
251 | } |
252 | } |
253 | |
254 | private double getDouble(Object o) { |
255 | if (o instanceof Double) |
256 | return (Double)o; |
257 | if (o instanceof Integer) |
258 | return (Integer)o; |
259 | throw new UnsupportedOperationException("Trying to cast a "+o.getClass().getCanonicalName()+" to a Double!"); |
260 | } |
261 | |
262 | private TypeEnum getDynamicType(Object o) { |
263 | if (o instanceof Integer) |
264 | return TypeEnum.INT; |
265 | if (o instanceof Double) |
266 | return TypeEnum.DOUBLE; |
267 | if (o instanceof String) |
268 | return TypeEnum.ENUM; |
269 | if (o instanceof Boolean) |
270 | return TypeEnum.BOOL; |
271 | throw new RuntimeException("Unknown dynamic type found! Should never happen!"); |
272 | } |
273 | |
274 | @Override |
275 | public Object caseTermExpression(TermExpression object) { |
276 | TypeEnum leftType = typeInferer.getType(object.getLeft()); |
277 | TypeEnum rightType = typeInferer.getType(object.getRight()); |
278 | Object left = doSwitch(object.getLeft()); |
279 | Object right = doSwitch(object.getRight()); |
280 | if (leftType == TypeEnum.ANY) leftType = getDynamicType(left); |
281 | if (rightType == TypeEnum.ANY) rightType = getDynamicType(right); |
282 | if (leftType == TypeEnum.INT && rightType == TypeEnum.INT) { |
283 | if (!(left instanceof Integer) || !(right instanceof Integer)) { |
284 | throw new TypesIncompatibleInTermException("Incompatible types in term expression. Expecting Integer!"); |
285 | } |
286 | int leftInt = (Integer)left; |
287 | int rightInt = (Integer)right; |
288 | switch(object.getOperation()) |
289 | { |
290 | case ADD: |
291 | return leftInt + rightInt; |
292 | case SUB: |
293 | return leftInt - rightInt; |
294 | } |
295 | throw new RuntimeException("This should never happen!"); |
296 | |
297 | } else { |
298 | double leftDouble = getDouble(left); |
299 | double rightDouble = getDouble(right); |
300 | switch(object.getOperation()) |
301 | { |
302 | case ADD: |
303 | return leftDouble + rightDouble; |
304 | case SUB: |
305 | return leftDouble - rightDouble; |
306 | } |
307 | throw new RuntimeException("This should never happen!"); |
308 | } |
309 | } |
310 | |
311 | @Override |
312 | public Object caseBooleanOperatorExpression(BooleanOperatorExpression object) { |
313 | boolean b1 = (Boolean) this.doSwitch(object.getLeft()); |
314 | boolean b2 = (Boolean) this.doSwitch(object.getRight()); |
315 | switch(object.getOperation()) { |
316 | case OR: |
317 | return b1 || b2; |
318 | case AND: |
319 | return b1 && b2; |
320 | case XOR: |
321 | return b1 ^ b2; |
322 | } |
323 | throw new RuntimeException("This should never happen!"); |
324 | } |
325 | |
326 | @Override |
327 | public Object caseNegativeExpression(NegativeExpression object) { |
328 | Object value = this.doSwitch(object.getInner()); |
329 | if (value instanceof Integer) |
330 | return -((Integer)value); |
331 | if (value instanceof Double) |
332 | return -((Double)value); |
333 | throw new RuntimeException("Type mismatch, unary minus only supported for numbers!"); |
334 | } |
335 | |
336 | @Override |
337 | public Object caseBoolLiteral(BoolLiteral object) { |
338 | return object.isValue(); |
339 | } |
340 | |
341 | @Override |
342 | public Object caseNotExpression(NotExpression object) { |
343 | Boolean b = (Boolean)this.doSwitch(object.getInner()); |
344 | return !b; |
345 | } |
346 | |
347 | @Override |
348 | public Object casePowerExpression(PowerExpression object) { |
349 | TypeEnum leftType = typeInferer.getType(object.getBase()); |
350 | TypeEnum rightType = typeInferer.getType(object.getExponent()); |
351 | Object leftExpr = doSwitch(object.getBase()); |
352 | Object rightExpr = doSwitch(object.getExponent()); |
353 | if (leftType == TypeEnum.ANY) leftType = getDynamicType(leftExpr); |
354 | if (rightType == TypeEnum.ANY) rightType = getDynamicType(rightExpr); |
355 | |
356 | if (leftType == TypeEnum.INT) |
357 | leftExpr = Double.valueOf( (((Integer)leftExpr).intValue())); |
358 | if (rightType == TypeEnum.INT) |
359 | rightExpr = Double.valueOf( (((Integer)rightExpr).intValue())); |
360 | return Math.pow((Double)leftExpr, (Double)rightExpr); |
361 | } |
362 | |
363 | @Override |
364 | public Object caseFunctionLiteral(FunctionLiteral object) { |
365 | String functionID = object.getId(); |
366 | ArrayList<Object> parameterValues = new ArrayList<Object>(); |
367 | for (Expression e : object.getParameters_FunctionLiteral()) { |
368 | parameterValues.add(this.doSwitch(e)); |
369 | } |
370 | return functionLib.evaluate(functionID,parameterValues); |
371 | } |
372 | |
373 | @Override |
374 | public Object caseIfElseExpression(IfElseExpression object) { |
375 | boolean cond = (Boolean)this.doSwitch(object.getConditionExpression()); |
376 | if (cond) |
377 | return this.doSwitch(object.getIfExpression()); |
378 | else |
379 | return this.doSwitch(object.getElseExpression()); |
380 | } |
381 | |
382 | } |