2 // GenericExpressionVisitor.cs
5 // Alexander Chebaturkin (chebaturkin@gmail.com)
7 // Copyright (C) 2012 Alexander Chebaturkin
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using Mono.CodeContracts.Static.DataStructures;
33 using Op = Mono.CodeContracts.Static.Analysis.Numerical.ExpressionOperator;
35 namespace Mono.CodeContracts.Static.Analysis.Numerical {
36 abstract class GenericExpressionVisitor<In, Out, Var, Expr> {
37 protected readonly IExpressionDecoder<Var, Expr> Decoder;
39 protected GenericExpressionVisitor (IExpressionDecoder<Var, Expr> decoder)
44 public virtual Out Visit (Expr expr, In data)
46 var op = Decoder.OperatorFor (expr);
49 return VisitConstant (expr, data);
51 return VisitVariable (Decoder.UnderlyingVariable (expr), expr, data);
53 return DispatchVisitNot (Decoder.LeftExpressionFor (expr), data);
55 return VisitAnd (Decoder.LeftExpressionFor (expr), Decoder.RightExpressionFor (expr),
58 return VisitOr (Decoder.LeftExpressionFor (expr), Decoder.RightExpressionFor (expr),
61 return VisitXor (Decoder.LeftExpressionFor (expr), Decoder.RightExpressionFor (expr),
64 return VisitLogicalAnd (Decoder.LeftExpressionFor (expr),
65 Decoder.RightExpressionFor (expr), expr, data);
67 return VisitLogicalOr (Decoder.LeftExpressionFor (expr),
68 Decoder.RightExpressionFor (expr), expr, data);
70 return VisitNotEqual (Decoder.LeftExpressionFor (expr),
71 Decoder.RightExpressionFor (expr), expr, data);
75 return DispatchVisitEqual (op, Decoder.LeftExpressionFor (expr),
76 Decoder.RightExpressionFor (expr), expr, data);
79 return DispatchCompare (VisitLessThan, Decoder.LeftExpressionFor (expr),
80 Decoder.RightExpressionFor (expr), expr, data);
81 case Op.LessEqualThan:
82 return DispatchCompare (VisitLessEqualThan, Decoder.LeftExpressionFor (expr),
83 Decoder.RightExpressionFor (expr), expr, data);
85 return DispatchCompare (VisitGreaterThan, Decoder.LeftExpressionFor (expr),
86 Decoder.RightExpressionFor (expr), expr, data);
87 case Op.GreaterEqualThan:
88 return DispatchCompare (VisitGreaterEqualThan, Decoder.LeftExpressionFor (expr),
89 Decoder.RightExpressionFor (expr), expr, data);
92 return VisitAddition (Decoder.LeftExpressionFor (expr),
93 Decoder.RightExpressionFor (expr), expr, data);
95 return VisitDivision (Decoder.LeftExpressionFor (expr),
96 Decoder.RightExpressionFor (expr), expr, data);
98 return VisitSubtraction (Decoder.LeftExpressionFor (expr),
99 Decoder.RightExpressionFor (expr), expr, data);
101 return VisitModulus (Decoder.LeftExpressionFor (expr), Decoder.RightExpressionFor (expr),
104 return VisitMultiply (Decoder.LeftExpressionFor (expr),
105 Decoder.RightExpressionFor (expr), expr, data);
108 return VisitSizeOf (Decoder.LeftExpressionFor (expr), data);
110 return VisitUnaryMinus (Decoder.LeftExpressionFor (expr), expr, data);
112 return VisitLogicalNot (Decoder.LeftExpressionFor (expr), expr, data);
114 return VisitUnknown (expr, data);
116 throw new ArgumentOutOfRangeException ();
120 public virtual Out VisitVariable (Var var, Expr expr, In data)
122 return Default (data);
125 public virtual Out VisitConstant (Expr expr, In data)
127 return Default (data);
130 public virtual Out VisitLogicalNot (Expr left, Expr original, In data)
132 return Default (data);
135 public virtual Out VisitUnaryMinus (Expr left, Expr original, In data)
137 return Default (data);
140 public virtual Out VisitNot (Expr expr, In data)
142 return Default (data);
145 public virtual Out VisitSizeOf (Expr expr, In data)
147 return Default (data);
150 public virtual Out VisitUnknown (Expr expr, In data)
152 return Default (data);
155 public virtual Out VisitLessThan (Expr left, Expr right, Expr original, In data)
157 return Default (data);
160 public virtual Out VisitLessEqualThan (Expr left, Expr right, Expr original, In data)
162 return Default (data);
165 public virtual Out VisitGreaterThan (Expr left, Expr right, Expr original, In data)
167 return DispatchCompare (VisitLessEqualThan, right, left, original, data);
170 public virtual Out VisitGreaterEqualThan (Expr left, Expr right, Expr original, In data)
172 return DispatchCompare (VisitLessThan, right, left, original, data);
175 public virtual Out VisitNotEqual (Expr left, Expr right, Expr original, In data)
177 return Default (data);
180 public virtual Out VisitAddition (Expr left, Expr right, Expr original, In data)
182 return Default (data);
185 public virtual Out VisitSubtraction (Expr left, Expr right, Expr original, In data)
187 return Default (data);
190 public virtual Out VisitMultiply (Expr left, Expr right, Expr original, In data)
192 return Default (data);
195 public virtual Out VisitModulus (Expr left, Expr right, Expr original, In data)
197 return Default (data);
200 public virtual Out VisitDivision (Expr left, Expr right, Expr original, In data)
202 return Default (data);
205 public virtual Out VisitEqual (Expr left, Expr right, Expr original, In data)
207 return Default (data);
210 public virtual Out VisitLogicalOr (Expr left, Expr right, Expr original, In data)
212 return Default (data);
215 public virtual Out VisitLogicalAnd (Expr left, Expr right, Expr original, In data)
217 return Default (data);
220 public virtual Out VisitXor (Expr left, Expr right, Expr original, In data)
222 return Default (data);
225 public virtual Out VisitOr (Expr left, Expr right, Expr original, In data)
227 return Default (data);
230 public virtual Out VisitAnd (Expr left, Expr right, Expr original, In data)
232 return Default (data);
235 protected virtual bool TryPolarity (Expr expr, In data, out bool shouldNegate)
237 if (Decoder.IsConstant (expr)) {
239 if (Decoder.TryValueOf (expr, ExpressionType.Int32, out intValue))
240 return true.With (intValue == 0, out shouldNegate);
243 if (Decoder.TryValueOf (expr, ExpressionType.Bool, out boolValue))
244 return true.With (boolValue, out shouldNegate);
247 return false.Without (out shouldNegate);
250 protected delegate Out CompareVisitor (Expr left, Expr right, Expr original, In data);
252 protected virtual Out DispatchCompare (CompareVisitor cmp, Expr left, Expr right, Expr original, In data)
254 if (Decoder.IsConstant (left) && Decoder.OperatorFor (right) == ExpressionOperator.Sub)
258 if (Decoder.TryValueOf (left, ExpressionType.Int32, out num) && num == 0)
259 // 0 OP (a-b) ==> b OP a
260 return cmp (Decoder.RightExpressionFor (right),
261 Decoder.LeftExpressionFor (right), right, data);
263 else if (Decoder.IsConstant (right) && Decoder.OperatorFor (left) == ExpressionOperator.Sub)
267 if (Decoder.TryValueOf (right, ExpressionType.Int32, out num) && num == 0)
268 // (a-b) OP 0 ==> a OP b
269 return cmp (Decoder.LeftExpressionFor (left),
270 Decoder.RightExpressionFor (left), left, data);
273 return cmp (left, right, original, data);
276 protected abstract Out Default (In data);
278 Out DispatchVisitNot (Expr expr, In data)
280 switch (Decoder.OperatorFor (expr)) {
281 case ExpressionOperator.Equal:
282 case ExpressionOperator.Equal_Obj:
283 return VisitNotEqual (Decoder.LeftExpressionFor (expr),
284 Decoder.RightExpressionFor (expr), expr, data);
285 case ExpressionOperator.LessThan: // a < b ==> b <= a
286 return DispatchCompare (VisitLessEqualThan, Decoder.RightExpressionFor (expr),
287 Decoder.LeftExpressionFor (expr), expr, data);
288 case ExpressionOperator.LessEqualThan: // a <= b ==> b < a
289 return DispatchCompare (VisitLessThan, Decoder.LeftExpressionFor (expr),
290 Decoder.RightExpressionFor (expr), expr, data);
291 case ExpressionOperator.GreaterThan: // a > b ==> b < a
292 return DispatchCompare (VisitLessThan, Decoder.RightExpressionFor (expr),
293 Decoder.LeftExpressionFor (expr), expr, data);
294 case ExpressionOperator.GreaterEqualThan: // a >= b ==> b <= a
295 return DispatchCompare (VisitLessEqualThan, Decoder.RightExpressionFor (expr),
296 Decoder.LeftExpressionFor (expr), expr, data);
298 return VisitNot (expr, data);
302 Out DispatchVisitEqual (ExpressionOperator eqKind, Expr left, Expr right, Expr original, In data)
304 // { left :eq: right }
305 switch (Decoder.OperatorFor (left)) {
306 case Op.GreaterEqualThan:
309 case Op.LessEqualThan:
312 // { ( a ?= b ) :eq: right }
314 if (TryPolarity (right, data, out shouldNegate))
315 // { (a ?= b) :eq: true => (a ?= b) }; (a ?= b) :eq: false => !(a ?= b) }
316 return shouldNegate ? DispatchVisitNot (left, data) : Visit (left, data);
320 switch (Decoder.OperatorFor (right)) {
321 case Op.GreaterEqualThan:
324 case Op.LessEqualThan:
327 // { left :eq: (a ?= b) }
329 if (TryPolarity (left, data, out shouldNegate))
330 // { true :eq: (a ?= b) => (a ?= b) }; false :eq: (a ?= b) => !(a ?= b) }
331 return shouldNegate ? DispatchVisitNot (right, data) : Visit (right, data);
335 return VisitEqual (left, right, original, data);