2008-02-18 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mcs / mcs / cfold.cs
1 //
2 // cfold.cs: Constant Folding
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //   Marek Safar (marek.safar@seznam.cz)
7 //
8 // (C) 2002, 2003 Ximian, Inc.
9 //
10
11 using System;
12
13 namespace Mono.CSharp {
14
15         public class ConstantFold {
16
17                 static Type[] binary_promotions = new Type[] { 
18                         TypeManager.decimal_type, TypeManager.double_type, TypeManager.float_type,
19                         TypeManager.uint64_type, TypeManager.int64_type, TypeManager.uint32_type };
20
21                 //
22                 // Performs the numeric promotions on the left and right expresions
23                 // and desposits the results on `lc' and `rc'.
24                 //
25                 // On success, the types of `lc' and `rc' on output will always match,
26                 // and the pair will be one of:
27                 //
28                 static void DoBinaryNumericPromotions (ref Constant left, ref Constant right)
29                 {
30                         Type ltype = left.Type;
31                         Type rtype = right.Type;
32
33                         foreach (Type t in binary_promotions) {
34                                 if (t == ltype || t == rtype) {
35                                         left = left.ConvertImplicitly (t);
36                                         right = right.ConvertImplicitly (t);
37                                         return;
38                                 }
39                         }
40
41                         left = left.ConvertImplicitly (TypeManager.int32_type);
42                         right = right.ConvertImplicitly (TypeManager.int32_type);
43                 }
44
45                 internal static void Error_CompileTimeOverflow (Location loc)
46                 {
47                         Report.Error (220, loc, "The operation overflows at compile time in checked mode");
48                 }
49                 
50                 /// <summary>
51                 ///   Constant expression folder for binary operations.
52                 ///
53                 ///   Returns null if the expression can not be folded.
54                 /// </summary>
55                 static public Constant BinaryFold (EmitContext ec, Binary.Operator oper,
56                                                      Constant left, Constant right, Location loc)
57                 {
58                         if (left is EmptyConstantCast)
59                                 return BinaryFold (ec, oper, ((EmptyConstantCast)left).child, right, loc);
60
61                         if (left is SideEffectConstant)
62                                 return BinaryFold (ec, oper, ((SideEffectConstant) left).left, right, loc);
63
64                         if (right is EmptyConstantCast)
65                                 return BinaryFold (ec, oper, left, ((EmptyConstantCast)right).child, loc);
66
67                         if (right is SideEffectConstant)
68                                 return BinaryFold (ec, oper, left, ((SideEffectConstant) right).left, loc);
69
70                         Type lt = left.Type;
71                         Type rt = right.Type;
72                         bool bool_res;
73                         Constant result = null;
74
75                         if (lt == TypeManager.bool_type && lt == rt) {
76                                 bool lv = ((BoolConstant) left ).Value;
77                                 bool rv = ((BoolConstant) right).Value;
78                                 switch (oper) {
79                                 case Binary.Operator.BitwiseAnd:
80                                 case Binary.Operator.LogicalAnd:
81                                         return new BoolConstant (lv && rv, left.Location);
82                                 case Binary.Operator.BitwiseOr:
83                                 case Binary.Operator.LogicalOr:
84                                         return new BoolConstant (lv || rv, left.Location);
85                                 case Binary.Operator.ExclusiveOr:
86                                         return new BoolConstant (lv ^ rv, left.Location);
87                                 case Binary.Operator.Equality:
88                                         return new BoolConstant (lv == rv, left.Location);
89                                 case Binary.Operator.Inequality:
90                                         return new BoolConstant (lv != rv, left.Location);
91                                 }
92                                 return null;
93                         }
94
95                         //
96                         // During an enum evaluation, none of the rules are valid
97                         // Not sure whether it is bug in csc or in documentation
98                         //
99                         if (ec.InEnumContext){
100                                 if (left is EnumConstant)
101                                         left = ((EnumConstant) left).Child;
102                                 
103                                 if (right is EnumConstant)
104                                         right = ((EnumConstant) right).Child;
105                         } else if (left is EnumConstant && rt == lt) {
106                                 switch (oper){
107                                         ///
108                                         /// E operator |(E x, E y);
109                                         /// E operator &(E x, E y);
110                                         /// E operator ^(E x, E y);
111                                         /// 
112                                         case Binary.Operator.BitwiseOr:
113                                         case Binary.Operator.BitwiseAnd:
114                                         case Binary.Operator.ExclusiveOr:
115                                                 return BinaryFold (ec, oper, ((EnumConstant)left).Child,
116                                                                 ((EnumConstant)right).Child, loc).TryReduce (ec, lt, loc);
117
118                                         ///
119                                         /// U operator -(E x, E y);
120                                         /// 
121                                         case Binary.Operator.Subtraction:
122                                                 result = BinaryFold (ec, oper, ((EnumConstant)left).Child, ((EnumConstant)right).Child, loc);
123                                                 return result.TryReduce (ec, ((EnumConstant)left).Child.Type, loc);
124
125                                         ///
126                                         /// bool operator ==(E x, E y);
127                                         /// bool operator !=(E x, E y);
128                                         /// bool operator <(E x, E y);
129                                         /// bool operator >(E x, E y);
130                                         /// bool operator <=(E x, E y);
131                                         /// bool operator >=(E x, E y);
132                                         /// 
133                                         case Binary.Operator.Equality:                          
134                                         case Binary.Operator.Inequality:
135                                         case Binary.Operator.LessThan:                          
136                                         case Binary.Operator.GreaterThan:
137                                         case Binary.Operator.LessThanOrEqual:                           
138                                         case Binary.Operator.GreaterThanOrEqual:
139                                                 return BinaryFold(ec, oper, ((EnumConstant)left).Child, ((EnumConstant)right).Child, loc);
140                                 }
141                                 return null;
142                         }
143
144                         switch (oper){
145                         case Binary.Operator.BitwiseOr:
146                                 DoBinaryNumericPromotions (ref left, ref right);
147                                 if (left == null || right == null)
148                                         return null;
149
150                                 if (left is IntConstant){
151                                         int res = ((IntConstant) left).Value | ((IntConstant) right).Value;
152                                         
153                                         return new IntConstant (res, left.Location);
154                                 }
155                                 if (left is UIntConstant){
156                                         uint res = ((UIntConstant)left).Value | ((UIntConstant)right).Value;
157                                         
158                                         return new UIntConstant (res, left.Location);
159                                 }
160                                 if (left is LongConstant){
161                                         long res = ((LongConstant)left).Value | ((LongConstant)right).Value;
162                                         
163                                         return new LongConstant (res, left.Location);
164                                 }
165                                 if (left is ULongConstant){
166                                         ulong res = ((ULongConstant)left).Value |
167                                                 ((ULongConstant)right).Value;
168                                         
169                                         return new ULongConstant (res, left.Location);
170                                 }
171                                 break;
172                                 
173                         case Binary.Operator.BitwiseAnd:
174                                 DoBinaryNumericPromotions (ref left, ref right);
175                                 if (left == null || right == null)
176                                         return null;
177                                 
178                                 ///
179                                 /// int operator &(int x, int y);
180                                 /// uint operator &(uint x, uint y);
181                                 /// long operator &(long x, long y);
182                                 /// ulong operator &(ulong x, ulong y);
183                                 ///
184                                 if (left is IntConstant){
185                                         int res = ((IntConstant) left).Value & ((IntConstant) right).Value;
186                                         return new IntConstant (res, left.Location);
187                                 }
188                                 if (left is UIntConstant){
189                                         uint res = ((UIntConstant)left).Value & ((UIntConstant)right).Value;
190                                         return new UIntConstant (res, left.Location);
191                                 }
192                                 if (left is LongConstant){
193                                         long res = ((LongConstant)left).Value & ((LongConstant)right).Value;
194                                         return new LongConstant (res, left.Location);
195                                 }
196                                 if (left is ULongConstant){
197                                         ulong res = ((ULongConstant)left).Value &
198                                                 ((ULongConstant)right).Value;
199                                         
200                                         return new ULongConstant (res, left.Location);
201                                 }
202                                 break;
203
204                         case Binary.Operator.ExclusiveOr:
205                                 DoBinaryNumericPromotions (ref left, ref right);
206                                 if (left == null || right == null)
207                                         return null;
208                                 
209                                 if (left is IntConstant){
210                                         int res = ((IntConstant) left).Value ^ ((IntConstant) right).Value;
211                                         return new IntConstant (res, left.Location);
212                                 }
213                                 if (left is UIntConstant){
214                                         uint res = ((UIntConstant)left).Value ^ ((UIntConstant)right).Value;
215                                         
216                                         return  new UIntConstant (res, left.Location);
217                                 }
218                                 if (left is LongConstant){
219                                         long res = ((LongConstant)left).Value ^ ((LongConstant)right).Value;
220                                         
221                                         return new LongConstant (res, left.Location);
222                                 }
223                                 if (left is ULongConstant){
224                                         ulong res = ((ULongConstant)left).Value ^
225                                                 ((ULongConstant)right).Value;
226                                         
227                                         return new ULongConstant (res, left.Location);
228                                 }
229                                 break;
230
231                         case Binary.Operator.Addition:
232                                 //
233                                 // If both sides are strings, then concatenate, if
234                                 // one is a string, and the other is not, then defer
235                                 // to runtime concatenation
236                                 //
237                                 if (lt == TypeManager.string_type || rt == TypeManager.string_type){
238                                         if (lt == TypeManager.string_type && rt == TypeManager.string_type)
239                                                 return new StringConstant (
240                                                         ((StringConstant) left).Value +
241                                                         ((StringConstant) right).Value, left.Location);
242                                         
243                                         return null;
244                                 }
245
246                                 //
247                                 // handle "E operator + (E x, U y)"
248                                 // handle "E operator + (Y y, E x)"
249                                 //
250                                 EnumConstant lc = left as EnumConstant;
251                                 EnumConstant rc = right as EnumConstant;
252                                 if (lc != null || rc != null){
253                                         if (lc == null) {
254                                                 lc = rc;
255                                                 lt = lc.Type;
256                                                 right = left;
257                                         }
258
259                                         // U has to be implicitly convetible to E.base
260                                         right = right.ConvertImplicitly (lc.Child.Type);
261                                         if (right == null)
262                                                 return null;
263
264                                         result = BinaryFold (ec, oper, lc.Child, right, loc);
265                                         if (result == null)
266                                                 return null;
267
268                                         result = result.TryReduce (ec, lt, loc);
269                                         if (result == null)
270                                                 return null;
271
272                                         return new EnumConstant (result, lt);
273                                 }
274
275                                 DoBinaryNumericPromotions (ref left, ref right);
276                                 if (left == null || right == null)
277                                         return null;
278
279                                 try {
280                                         if (left is DoubleConstant){
281                                                 double res;
282                                                 
283                                                 if (ec.ConstantCheckState)
284                                                         res = checked (((DoubleConstant) left).Value +
285                                                                        ((DoubleConstant) right).Value);
286                                                 else
287                                                         res = unchecked (((DoubleConstant) left).Value +
288                                                                          ((DoubleConstant) right).Value);
289                                                 
290                                                 return new DoubleConstant (res, left.Location);
291                                         }
292                                         if (left is FloatConstant){
293                                                 float res;
294                                                 
295                                                 if (ec.ConstantCheckState)
296                                                         res = checked (((FloatConstant) left).Value +
297                                                                        ((FloatConstant) right).Value);
298                                                 else
299                                                         res = unchecked (((FloatConstant) left).Value +
300                                                                          ((FloatConstant) right).Value);
301                                                 
302                                                 result = new FloatConstant (res, left.Location);
303                                         } else if (left is ULongConstant){
304                                                 ulong res;
305                                                 
306                                                 if (ec.ConstantCheckState)
307                                                         res = checked (((ULongConstant) left).Value +
308                                                                        ((ULongConstant) right).Value);
309                                                 else
310                                                         res = unchecked (((ULongConstant) left).Value +
311                                                                          ((ULongConstant) right).Value);
312
313                                                 result = new ULongConstant (res, left.Location);
314                                         } else if (left is LongConstant){
315                                                 long res;
316                                                 
317                                                 if (ec.ConstantCheckState)
318                                                         res = checked (((LongConstant) left).Value +
319                                                                        ((LongConstant) right).Value);
320                                                 else
321                                                         res = unchecked (((LongConstant) left).Value +
322                                                                          ((LongConstant) right).Value);
323                                                 
324                                                 result = new LongConstant (res, left.Location);
325                                         } else if (left is UIntConstant){
326                                                 uint res;
327                                                 
328                                                 if (ec.ConstantCheckState)
329                                                         res = checked (((UIntConstant) left).Value +
330                                                                        ((UIntConstant) right).Value);
331                                                 else
332                                                         res = unchecked (((UIntConstant) left).Value +
333                                                                          ((UIntConstant) right).Value);
334                                                 
335                                                 result = new UIntConstant (res, left.Location);
336                                         } else if (left is IntConstant){
337                                                 int res;
338
339                                                 if (ec.ConstantCheckState)
340                                                         res = checked (((IntConstant) left).Value +
341                                                                        ((IntConstant) right).Value);
342                                                 else
343                                                         res = unchecked (((IntConstant) left).Value +
344                                                                          ((IntConstant) right).Value);
345
346                                                 result = new IntConstant (res, left.Location);
347                                         } else if (left is DecimalConstant) {
348                                                 decimal res;
349
350                                                 if (ec.ConstantCheckState)
351                                                         res = checked (((DecimalConstant) left).Value +
352                                                                 ((DecimalConstant) right).Value);
353                                                 else
354                                                         res = unchecked (((DecimalConstant) left).Value +
355                                                                 ((DecimalConstant) right).Value);
356
357                                                 result = new DecimalConstant (res, left.Location);
358                                         } else {
359                                                 throw new Exception ( "Unexepected addition input: " + left);
360                                         }
361                                 } catch (OverflowException){
362                                         Error_CompileTimeOverflow (loc);
363                                 }
364
365                                 return result;
366
367                         case Binary.Operator.Subtraction:
368                                 //
369                                 // handle "E operator - (E x, U y)"
370                                 // handle "E operator - (Y y, E x)"
371                                 //
372                                 lc = left as EnumConstant;
373                                 rc = right as EnumConstant;
374                                 if (lc != null || rc != null){
375                                         if (lc == null) {
376                                                 lc = rc;
377                                                 lt = lc.Type;
378                                                 right = left;
379                                         }
380
381                                         // U has to be implicitly convetible to E.base
382                                         right = right.ConvertImplicitly (lc.Child.Type);
383                                         if (right == null)
384                                                 return null;
385
386                                         result = BinaryFold (ec, oper, lc.Child, right, loc);
387                                         if (result == null)
388                                                 return null;
389
390                                         result = result.TryReduce (ec, lt, loc);
391                                         if (result == null)
392                                                 return null;
393
394                                         return new EnumConstant (result, lt);
395                                 }
396
397                                 DoBinaryNumericPromotions (ref left, ref right);
398                                 if (left == null || right == null)
399                                         return null;
400
401                                 try {
402                                         if (left is DoubleConstant){
403                                                 double res;
404                                                 
405                                                 if (ec.ConstantCheckState)
406                                                         res = checked (((DoubleConstant) left).Value -
407                                                                        ((DoubleConstant) right).Value);
408                                                 else
409                                                         res = unchecked (((DoubleConstant) left).Value -
410                                                                          ((DoubleConstant) right).Value);
411                                                 
412                                                 result = new DoubleConstant (res, left.Location);
413                                         } else if (left is FloatConstant){
414                                                 float res;
415                                                 
416                                                 if (ec.ConstantCheckState)
417                                                         res = checked (((FloatConstant) left).Value -
418                                                                        ((FloatConstant) right).Value);
419                                                 else
420                                                         res = unchecked (((FloatConstant) left).Value -
421                                                                          ((FloatConstant) right).Value);
422                                                 
423                                                 result = new FloatConstant (res, left.Location);
424                                         } else if (left is ULongConstant){
425                                                 ulong res;
426                                                 
427                                                 if (ec.ConstantCheckState)
428                                                         res = checked (((ULongConstant) left).Value -
429                                                                        ((ULongConstant) right).Value);
430                                                 else
431                                                         res = unchecked (((ULongConstant) left).Value -
432                                                                          ((ULongConstant) right).Value);
433                                                 
434                                                 result = new ULongConstant (res, left.Location);
435                                         } else if (left is LongConstant){
436                                                 long res;
437                                                 
438                                                 if (ec.ConstantCheckState)
439                                                         res = checked (((LongConstant) left).Value -
440                                                                        ((LongConstant) right).Value);
441                                                 else
442                                                         res = unchecked (((LongConstant) left).Value -
443                                                                          ((LongConstant) right).Value);
444                                                 
445                                                 result = new LongConstant (res, left.Location);
446                                         } else if (left is UIntConstant){
447                                                 uint res;
448                                                 
449                                                 if (ec.ConstantCheckState)
450                                                         res = checked (((UIntConstant) left).Value -
451                                                                        ((UIntConstant) right).Value);
452                                                 else
453                                                         res = unchecked (((UIntConstant) left).Value -
454                                                                          ((UIntConstant) right).Value);
455                                                 
456                                                 result = new UIntConstant (res, left.Location);
457                                         } else if (left is IntConstant){
458                                                 int res;
459
460                                                 if (ec.ConstantCheckState)
461                                                         res = checked (((IntConstant) left).Value -
462                                                                        ((IntConstant) right).Value);
463                                                 else
464                                                         res = unchecked (((IntConstant) left).Value -
465                                                                          ((IntConstant) right).Value);
466
467                                                 result = new IntConstant (res, left.Location);
468                                         } else if (left is DecimalConstant) {
469                                                 decimal res;
470
471                                                 if (ec.ConstantCheckState)
472                                                         res = checked (((DecimalConstant) left).Value -
473                                                                 ((DecimalConstant) right).Value);
474                                                 else
475                                                         res = unchecked (((DecimalConstant) left).Value -
476                                                                 ((DecimalConstant) right).Value);
477
478                                                 return new DecimalConstant (res, left.Location);
479                                         } else {
480                                                 throw new Exception ( "Unexepected subtraction input: " + left);
481                                         }
482                                 } catch (OverflowException){
483                                         Error_CompileTimeOverflow (loc);
484                                 }
485
486                                 return result;
487                                 
488                         case Binary.Operator.Multiply:
489                                 DoBinaryNumericPromotions (ref left, ref right);
490                                 if (left == null || right == null)
491                                         return null;
492
493                                 try {
494                                         if (left is DoubleConstant){
495                                                 double res;
496                                                 
497                                                 if (ec.ConstantCheckState)
498                                                         res = checked (((DoubleConstant) left).Value *
499                                                                 ((DoubleConstant) right).Value);
500                                                 else
501                                                         res = unchecked (((DoubleConstant) left).Value *
502                                                                 ((DoubleConstant) right).Value);
503                                                 
504                                                 return new DoubleConstant (res, left.Location);
505                                         } else if (left is FloatConstant){
506                                                 float res;
507                                                 
508                                                 if (ec.ConstantCheckState)
509                                                         res = checked (((FloatConstant) left).Value *
510                                                                 ((FloatConstant) right).Value);
511                                                 else
512                                                         res = unchecked (((FloatConstant) left).Value *
513                                                                 ((FloatConstant) right).Value);
514                                                 
515                                                 return new FloatConstant (res, left.Location);
516                                         } else if (left is ULongConstant){
517                                                 ulong res;
518                                                 
519                                                 if (ec.ConstantCheckState)
520                                                         res = checked (((ULongConstant) left).Value *
521                                                                 ((ULongConstant) right).Value);
522                                                 else
523                                                         res = unchecked (((ULongConstant) left).Value *
524                                                                 ((ULongConstant) right).Value);
525                                                 
526                                                 return new ULongConstant (res, left.Location);
527                                         } else if (left is LongConstant){
528                                                 long res;
529                                                 
530                                                 if (ec.ConstantCheckState)
531                                                         res = checked (((LongConstant) left).Value *
532                                                                 ((LongConstant) right).Value);
533                                                 else
534                                                         res = unchecked (((LongConstant) left).Value *
535                                                                 ((LongConstant) right).Value);
536                                                 
537                                                 return new LongConstant (res, left.Location);
538                                         } else if (left is UIntConstant){
539                                                 uint res;
540                                                 
541                                                 if (ec.ConstantCheckState)
542                                                         res = checked (((UIntConstant) left).Value *
543                                                                 ((UIntConstant) right).Value);
544                                                 else
545                                                         res = unchecked (((UIntConstant) left).Value *
546                                                                 ((UIntConstant) right).Value);
547                                                 
548                                                 return new UIntConstant (res, left.Location);
549                                         } else if (left is IntConstant){
550                                                 int res;
551
552                                                 if (ec.ConstantCheckState)
553                                                         res = checked (((IntConstant) left).Value *
554                                                                 ((IntConstant) right).Value);
555                                                 else
556                                                         res = unchecked (((IntConstant) left).Value *
557                                                                 ((IntConstant) right).Value);
558
559                                                 return new IntConstant (res, left.Location);
560                                         } else if (left is DecimalConstant) {
561                                                 decimal res;
562
563                                                 if (ec.ConstantCheckState)
564                                                         res = checked (((DecimalConstant) left).Value *
565                                                                 ((DecimalConstant) right).Value);
566                                                 else
567                                                         res = unchecked (((DecimalConstant) left).Value *
568                                                                 ((DecimalConstant) right).Value);
569
570                                                 return new DecimalConstant (res, left.Location);
571                                         } else {
572                                                 throw new Exception ( "Unexepected multiply input: " + left);
573                                         }
574                                 } catch (OverflowException){
575                                         Error_CompileTimeOverflow (loc);
576                                 }
577                                 break;
578
579                         case Binary.Operator.Division:
580                                 DoBinaryNumericPromotions (ref left, ref right);
581                                 if (left == null || right == null)
582                                         return null;
583
584                                 try {
585                                         if (left is DoubleConstant){
586                                                 double res;
587                                                 
588                                                 if (ec.ConstantCheckState)
589                                                         res = checked (((DoubleConstant) left).Value /
590                                                                 ((DoubleConstant) right).Value);
591                                                 else
592                                                         res = unchecked (((DoubleConstant) left).Value /
593                                                                 ((DoubleConstant) right).Value);
594                                                 
595                                                 return new DoubleConstant (res, left.Location);
596                                         } else if (left is FloatConstant){
597                                                 float res;
598                                                 
599                                                 if (ec.ConstantCheckState)
600                                                         res = checked (((FloatConstant) left).Value /
601                                                                 ((FloatConstant) right).Value);
602                                                 else
603                                                         res = unchecked (((FloatConstant) left).Value /
604                                                                 ((FloatConstant) right).Value);
605                                                 
606                                                 return new FloatConstant (res, left.Location);
607                                         } else if (left is ULongConstant){
608                                                 ulong res;
609                                                 
610                                                 if (ec.ConstantCheckState)
611                                                         res = checked (((ULongConstant) left).Value /
612                                                                 ((ULongConstant) right).Value);
613                                                 else
614                                                         res = unchecked (((ULongConstant) left).Value /
615                                                                 ((ULongConstant) right).Value);
616                                                 
617                                                 return new ULongConstant (res, left.Location);
618                                         } else if (left is LongConstant){
619                                                 long res;
620                                                 
621                                                 if (ec.ConstantCheckState)
622                                                         res = checked (((LongConstant) left).Value /
623                                                                 ((LongConstant) right).Value);
624                                                 else
625                                                         res = unchecked (((LongConstant) left).Value /
626                                                                 ((LongConstant) right).Value);
627                                                 
628                                                 return new LongConstant (res, left.Location);
629                                         } else if (left is UIntConstant){
630                                                 uint res;
631                                                 
632                                                 if (ec.ConstantCheckState)
633                                                         res = checked (((UIntConstant) left).Value /
634                                                                 ((UIntConstant) right).Value);
635                                                 else
636                                                         res = unchecked (((UIntConstant) left).Value /
637                                                                 ((UIntConstant) right).Value);
638                                                 
639                                                 return new UIntConstant (res, left.Location);
640                                         } else if (left is IntConstant){
641                                                 int res;
642
643                                                 if (ec.ConstantCheckState)
644                                                         res = checked (((IntConstant) left).Value /
645                                                                 ((IntConstant) right).Value);
646                                                 else
647                                                         res = unchecked (((IntConstant) left).Value /
648                                                                 ((IntConstant) right).Value);
649
650                                                 return new IntConstant (res, left.Location);
651                                         } else if (left is DecimalConstant) {
652                                                 decimal res;
653
654                                                 if (ec.ConstantCheckState)
655                                                         res = checked (((DecimalConstant) left).Value /
656                                                                 ((DecimalConstant) right).Value);
657                                                 else
658                                                         res = unchecked (((DecimalConstant) left).Value /
659                                                                 ((DecimalConstant) right).Value);
660
661                                                 return new DecimalConstant (res, left.Location);
662                                         } else {
663                                                 throw new Exception ( "Unexepected division input: " + left);
664                                         }
665                                 } catch (OverflowException){
666                                         Error_CompileTimeOverflow (loc);
667
668                                 } catch (DivideByZeroException) {
669                                         Report.Error (020, loc, "Division by constant zero");
670                                 }
671                                 
672                                 break;
673                                 
674                         case Binary.Operator.Modulus:
675                                 DoBinaryNumericPromotions (ref left, ref right);
676                                 if (left == null || right == null)
677                                         return null;
678
679                                 try {
680                                         if (left is DoubleConstant){
681                                                 double res;
682                                                 
683                                                 if (ec.ConstantCheckState)
684                                                         res = checked (((DoubleConstant) left).Value %
685                                                                        ((DoubleConstant) right).Value);
686                                                 else
687                                                         res = unchecked (((DoubleConstant) left).Value %
688                                                                          ((DoubleConstant) right).Value);
689                                                 
690                                                 return new DoubleConstant (res, left.Location);
691                                         } else if (left is FloatConstant){
692                                                 float res;
693                                                 
694                                                 if (ec.ConstantCheckState)
695                                                         res = checked (((FloatConstant) left).Value %
696                                                                        ((FloatConstant) right).Value);
697                                                 else
698                                                         res = unchecked (((FloatConstant) left).Value %
699                                                                          ((FloatConstant) right).Value);
700                                                 
701                                                 return new FloatConstant (res, left.Location);
702                                         } else if (left is ULongConstant){
703                                                 ulong res;
704                                                 
705                                                 if (ec.ConstantCheckState)
706                                                         res = checked (((ULongConstant) left).Value %
707                                                                        ((ULongConstant) right).Value);
708                                                 else
709                                                         res = unchecked (((ULongConstant) left).Value %
710                                                                          ((ULongConstant) right).Value);
711                                                 
712                                                 return new ULongConstant (res, left.Location);
713                                         } else if (left is LongConstant){
714                                                 long res;
715                                                 
716                                                 if (ec.ConstantCheckState)
717                                                         res = checked (((LongConstant) left).Value %
718                                                                        ((LongConstant) right).Value);
719                                                 else
720                                                         res = unchecked (((LongConstant) left).Value %
721                                                                          ((LongConstant) right).Value);
722                                                 
723                                                 return new LongConstant (res, left.Location);
724                                         } else if (left is UIntConstant){
725                                                 uint res;
726                                                 
727                                                 if (ec.ConstantCheckState)
728                                                         res = checked (((UIntConstant) left).Value %
729                                                                        ((UIntConstant) right).Value);
730                                                 else
731                                                         res = unchecked (((UIntConstant) left).Value %
732                                                                          ((UIntConstant) right).Value);
733                                                 
734                                                 return new UIntConstant (res, left.Location);
735                                         } else if (left is IntConstant){
736                                                 int res;
737
738                                                 if (ec.ConstantCheckState)
739                                                         res = checked (((IntConstant) left).Value %
740                                                                        ((IntConstant) right).Value);
741                                                 else
742                                                         res = unchecked (((IntConstant) left).Value %
743                                                                          ((IntConstant) right).Value);
744
745                                                 return new IntConstant (res, left.Location);
746                                         } else {
747                                                 throw new Exception ( "Unexepected modulus input: " + left);
748                                         }
749                                 } catch (DivideByZeroException){
750                                         Report.Error (020, loc, "Division by constant zero");
751                                 } catch (OverflowException){
752                                         Error_CompileTimeOverflow (loc);
753                                 }
754                                 break;
755
756                                 //
757                                 // There is no overflow checking on left shift
758                                 //
759                         case Binary.Operator.LeftShift:
760                                 IntConstant ic = right.ConvertImplicitly (TypeManager.int32_type) as IntConstant;
761                                 if (ic == null){
762                                         Binary.Error_OperatorCannotBeApplied (loc, "<<", lt, rt);
763                                         return null;
764                                 }
765
766                                 int lshift_val = ic.Value;
767                                 if (left.Type == TypeManager.uint64_type)
768                                         return new ULongConstant (((ULongConstant)left).Value << lshift_val, left.Location);
769                                 if (left.Type == TypeManager.int64_type)
770                                         return new LongConstant (((LongConstant)left).Value << lshift_val, left.Location);
771                                 if (left.Type == TypeManager.uint32_type)
772                                         return new UIntConstant (((UIntConstant)left).Value << lshift_val, left.Location);
773
774                                 left = left.ConvertImplicitly (TypeManager.int32_type);
775                                 if (left.Type == TypeManager.int32_type)
776                                         return new IntConstant (((IntConstant)left).Value << lshift_val, left.Location);
777
778                                 Binary.Error_OperatorCannotBeApplied (loc, "<<", lt, rt);
779                                 break;
780
781                                 //
782                                 // There is no overflow checking on right shift
783                                 //
784                         case Binary.Operator.RightShift:
785                                 IntConstant sic = right.ConvertImplicitly (TypeManager.int32_type) as IntConstant;
786                                 if (sic == null){
787                                         Binary.Error_OperatorCannotBeApplied (loc, ">>", lt, rt);
788                                         return null;
789                                 }
790                                 int rshift_val = sic.Value;
791                                 if (left.Type == TypeManager.uint64_type)
792                                         return new ULongConstant (((ULongConstant)left).Value >> rshift_val, left.Location);
793                                 if (left.Type == TypeManager.int64_type)
794                                         return new LongConstant (((LongConstant)left).Value >> rshift_val, left.Location);
795                                 if (left.Type == TypeManager.uint32_type)
796                                         return new UIntConstant (((UIntConstant)left).Value >> rshift_val, left.Location);
797
798                                 left = left.ConvertImplicitly (TypeManager.int32_type);
799                                 if (left.Type == TypeManager.int32_type)
800                                         return new IntConstant (((IntConstant)left).Value >> rshift_val, left.Location);
801
802                                 Binary.Error_OperatorCannotBeApplied (loc, ">>", lt, rt);
803                                 break;
804
805                         case Binary.Operator.Equality:
806                                 if (left is NullConstant){
807                                         if (right is NullConstant)
808                                                 return new BoolConstant (true, left.Location);
809                                         else if (right is StringConstant)
810                                                 return new BoolConstant (
811                                                         ((StringConstant) right).Value == null, left.Location);
812                                 } else if (right is NullConstant){
813                                         if (left is NullConstant)
814                                                 return new BoolConstant (true, left.Location);
815                                         else if (left is StringConstant)
816                                                 return new BoolConstant (
817                                                         ((StringConstant) left).Value == null, left.Location);
818                                 }
819                                 if (left is StringConstant && right is StringConstant){
820                                         return new BoolConstant (
821                                                 ((StringConstant) left).Value ==
822                                                 ((StringConstant) right).Value, left.Location);
823                                         
824                                 }
825
826                                 DoBinaryNumericPromotions (ref left, ref right);
827                                 if (left == null || right == null)
828                                         return null;
829
830                                 bool_res = false;
831                                 if (left is DoubleConstant)
832                                         bool_res = ((DoubleConstant) left).Value ==
833                                                 ((DoubleConstant) right).Value;
834                                 else if (left is FloatConstant)
835                                         bool_res = ((FloatConstant) left).Value ==
836                                                 ((FloatConstant) right).Value;
837                                 else if (left is ULongConstant)
838                                         bool_res = ((ULongConstant) left).Value ==
839                                                 ((ULongConstant) right).Value;
840                                 else if (left is LongConstant)
841                                         bool_res = ((LongConstant) left).Value ==
842                                                 ((LongConstant) right).Value;
843                                 else if (left is UIntConstant)
844                                         bool_res = ((UIntConstant) left).Value ==
845                                                 ((UIntConstant) right).Value;
846                                 else if (left is IntConstant)
847                                         bool_res = ((IntConstant) left).Value ==
848                                                 ((IntConstant) right).Value;
849                                 else
850                                         return null;
851
852                                 return new BoolConstant (bool_res, left.Location);
853
854                         case Binary.Operator.Inequality:
855                                 if (left is NullConstant){
856                                         if (right is NullConstant)
857                                                 return new BoolConstant (false, left.Location);
858                                         else if (right is StringConstant)
859                                                 return new BoolConstant (
860                                                         ((StringConstant) right).Value != null, left.Location);
861                                 } else if (right is NullConstant){
862                                         if (left is NullConstant)
863                                                 return new BoolConstant (false, left.Location);
864                                         else if (left is StringConstant)
865                                                 return new BoolConstant (
866                                                         ((StringConstant) left).Value != null, left.Location);
867                                 }
868                                 if (left is StringConstant && right is StringConstant){
869                                         return new BoolConstant (
870                                                 ((StringConstant) left).Value !=
871                                                 ((StringConstant) right).Value, left.Location);
872                                         
873                                 }
874
875                                 DoBinaryNumericPromotions (ref left, ref right);
876                                 if (left == null || right == null)
877                                         return null;
878
879                                 bool_res = false;
880                                 if (left is DoubleConstant)
881                                         bool_res = ((DoubleConstant) left).Value !=
882                                                 ((DoubleConstant) right).Value;
883                                 else if (left is FloatConstant)
884                                         bool_res = ((FloatConstant) left).Value !=
885                                                 ((FloatConstant) right).Value;
886                                 else if (left is ULongConstant)
887                                         bool_res = ((ULongConstant) left).Value !=
888                                                 ((ULongConstant) right).Value;
889                                 else if (left is LongConstant)
890                                         bool_res = ((LongConstant) left).Value !=
891                                                 ((LongConstant) right).Value;
892                                 else if (left is UIntConstant)
893                                         bool_res = ((UIntConstant) left).Value !=
894                                                 ((UIntConstant) right).Value;
895                                 else if (left is IntConstant)
896                                         bool_res = ((IntConstant) left).Value !=
897                                                 ((IntConstant) right).Value;
898                                 else
899                                         return null;
900
901                                 return new BoolConstant (bool_res, left.Location);
902
903                         case Binary.Operator.LessThan:
904                                 DoBinaryNumericPromotions (ref left, ref right);
905                                 if (left == null || right == null)
906                                         return null;
907
908                                 bool_res = false;
909                                 if (left is DoubleConstant)
910                                         bool_res = ((DoubleConstant) left).Value <
911                                                 ((DoubleConstant) right).Value;
912                                 else if (left is FloatConstant)
913                                         bool_res = ((FloatConstant) left).Value <
914                                                 ((FloatConstant) right).Value;
915                                 else if (left is ULongConstant)
916                                         bool_res = ((ULongConstant) left).Value <
917                                                 ((ULongConstant) right).Value;
918                                 else if (left is LongConstant)
919                                         bool_res = ((LongConstant) left).Value <
920                                                 ((LongConstant) right).Value;
921                                 else if (left is UIntConstant)
922                                         bool_res = ((UIntConstant) left).Value <
923                                                 ((UIntConstant) right).Value;
924                                 else if (left is IntConstant)
925                                         bool_res = ((IntConstant) left).Value <
926                                                 ((IntConstant) right).Value;
927                                 else
928                                         return null;
929
930                                 return new BoolConstant (bool_res, left.Location);
931                                 
932                         case Binary.Operator.GreaterThan:
933                                 DoBinaryNumericPromotions (ref left, ref right);
934                                 if (left == null || right == null)
935                                         return null;
936
937                                 bool_res = false;
938                                 if (left is DoubleConstant)
939                                         bool_res = ((DoubleConstant) left).Value >
940                                                 ((DoubleConstant) right).Value;
941                                 else if (left is FloatConstant)
942                                         bool_res = ((FloatConstant) left).Value >
943                                                 ((FloatConstant) right).Value;
944                                 else if (left is ULongConstant)
945                                         bool_res = ((ULongConstant) left).Value >
946                                                 ((ULongConstant) right).Value;
947                                 else if (left is LongConstant)
948                                         bool_res = ((LongConstant) left).Value >
949                                                 ((LongConstant) right).Value;
950                                 else if (left is UIntConstant)
951                                         bool_res = ((UIntConstant) left).Value >
952                                                 ((UIntConstant) right).Value;
953                                 else if (left is IntConstant)
954                                         bool_res = ((IntConstant) left).Value >
955                                                 ((IntConstant) right).Value;
956                                 else
957                                         return null;
958
959                                 return new BoolConstant (bool_res, left.Location);
960
961                         case Binary.Operator.GreaterThanOrEqual:
962                                 DoBinaryNumericPromotions (ref left, ref right);
963                                 if (left == null || right == null)
964                                         return null;
965
966                                 bool_res = false;
967                                 if (left is DoubleConstant)
968                                         bool_res = ((DoubleConstant) left).Value >=
969                                                 ((DoubleConstant) right).Value;
970                                 else if (left is FloatConstant)
971                                         bool_res = ((FloatConstant) left).Value >=
972                                                 ((FloatConstant) right).Value;
973                                 else if (left is ULongConstant)
974                                         bool_res = ((ULongConstant) left).Value >=
975                                                 ((ULongConstant) right).Value;
976                                 else if (left is LongConstant)
977                                         bool_res = ((LongConstant) left).Value >=
978                                                 ((LongConstant) right).Value;
979                                 else if (left is UIntConstant)
980                                         bool_res = ((UIntConstant) left).Value >=
981                                                 ((UIntConstant) right).Value;
982                                 else if (left is IntConstant)
983                                         bool_res = ((IntConstant) left).Value >=
984                                                 ((IntConstant) right).Value;
985                                 else
986                                         return null;
987
988                                 return new BoolConstant (bool_res, left.Location);
989
990                         case Binary.Operator.LessThanOrEqual:
991                                 DoBinaryNumericPromotions (ref left, ref right);
992                                 if (left == null || right == null)
993                                         return null;
994
995                                 bool_res = false;
996                                 if (left is DoubleConstant)
997                                         bool_res = ((DoubleConstant) left).Value <=
998                                                 ((DoubleConstant) right).Value;
999                                 else if (left is FloatConstant)
1000                                         bool_res = ((FloatConstant) left).Value <=
1001                                                 ((FloatConstant) right).Value;
1002                                 else if (left is ULongConstant)
1003                                         bool_res = ((ULongConstant) left).Value <=
1004                                                 ((ULongConstant) right).Value;
1005                                 else if (left is LongConstant)
1006                                         bool_res = ((LongConstant) left).Value <=
1007                                                 ((LongConstant) right).Value;
1008                                 else if (left is UIntConstant)
1009                                         bool_res = ((UIntConstant) left).Value <=
1010                                                 ((UIntConstant) right).Value;
1011                                 else if (left is IntConstant)
1012                                         bool_res = ((IntConstant) left).Value <=
1013                                                 ((IntConstant) right).Value;
1014                                 else
1015                                         return null;
1016
1017                                 return new BoolConstant (bool_res, left.Location);
1018                         }
1019                                         
1020                         return null;
1021                 }
1022         }
1023 }