2006-10-04 Martin Baulig <martin@ximian.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                 //
18                 // Performs the numeric promotions on the left and right expresions
19                 // and desposits the results on `lc' and `rc'.
20                 //
21                 // On success, the types of `lc' and `rc' on output will always match,
22                 // and the pair will be one of:
23                 //
24                 //   (double, double)
25                 //   (float, float)
26                 //   (ulong, ulong)
27                 //   (long, long)
28                 //   (uint, uint)
29                 //   (int, int)
30                 //   (short, short)   (Happens with enumerations with underlying short type)
31                 //   (ushort, ushort) (Happens with enumerations with underlying short type)
32                 //
33                 static void DoConstantNumericPromotions (EmitContext ec, Binary.Operator oper,
34                                                          ref Constant left, ref Constant right,
35                                                          Location loc)
36                 {
37                         if (left is DoubleConstant || right is DoubleConstant){
38                                 //
39                                 // If either side is a double, convert the other to a double
40                                 //
41                                 if (!(left is DoubleConstant))
42                                         left = left.ToDouble (loc);
43
44                                 if (!(right is DoubleConstant))
45                                         right = right.ToDouble (loc);
46                                 return;
47                         } else if (left is FloatConstant || right is FloatConstant) {
48                                 //
49                                 // If either side is a float, convert the other to a float
50                                 //
51                                 if (!(left is FloatConstant))
52                                         left = left.ToFloat (loc);
53
54                                 if (!(right is FloatConstant))
55                                         right = right.ToFloat (loc);
56 ;                               return;
57                         } else if (left is ULongConstant || right is ULongConstant){
58                                 //
59                                 // If either operand is of type ulong, the other operand is
60                                 // converted to type ulong.  or an error ocurrs if the other
61                                 // operand is of type sbyte, short, int or long
62                                 //
63 #if WRONG
64                                 Constant match, other;
65 #endif
66                                         
67                                 if (left is ULongConstant){
68 #if WRONG
69                                         other = right;
70                                         match = left;
71 #endif
72                                         if (!(right is ULongConstant))
73                                                 right = right.ToULong (loc);
74                                 } else {
75 #if WRONG
76                                         other = left;
77                                         match = right;
78 #endif
79                                         left = left.ToULong (loc);
80                                 }
81
82 #if WRONG
83                                 if (other is SByteConstant || other is ShortConstant ||
84                                     other is IntConstant || other is LongConstant){
85                                         Binary.Error_OperatorAmbiguous
86                                                 (loc, oper, other.Type, match.Type);
87                                         left = null;
88                                         right = null;
89                                 }
90 #endif
91                                 return;
92                         } else if (left is LongConstant || right is LongConstant){
93                                 //
94                                 // If either operand is of type long, the other operand is converted
95                                 // to type long.
96                                 //
97                                 if (!(left is LongConstant))
98                                         left = left.ToLong (loc);
99                                 else if (!(right is LongConstant))
100                                         right = right.ToLong (loc);
101                                 return;
102                         } else if (left is UIntConstant || right is UIntConstant){
103                                 //
104                                 // If either operand is of type uint, and the other
105                                 // operand is of type sbyte, short or int, the operands are
106                                 // converted to type long.
107                                 //
108                                 Constant other;
109                                 if (left is UIntConstant)
110                                         other = right;
111                                 else
112                                         other = left;
113
114                                 // Nothing to do.
115                                 if (other is UIntConstant)
116                                         return;
117
118                                 IntConstant ic = other as IntConstant;
119                                 if (ic != null){
120                                         if (ic.Value >= 0){
121                                                 if (left == other)
122                                                         left = new UIntConstant ((uint) ic.Value, ic.Location);
123                                                 else
124                                                         right = new UIntConstant ((uint) ic.Value, ic.Location);
125                                                 return;
126                                         }
127                                 }
128                                 
129                                 if (other is SByteConstant || other is ShortConstant || ic != null){
130                                         left = left.ToLong (loc);
131                                         right = right.ToLong (loc);
132                                 } else {
133                                         left = left.ToUInt (loc);
134                                         right = left.ToUInt (loc);
135                                 }
136
137                                 return;
138                         } else if (left is DecimalConstant || right is DecimalConstant) {
139                                 if (!(left is DecimalConstant))
140                                         left = left.ToDecimal (loc);
141                                 else if (!(right is DecimalConstant))
142                                         right = right.ToDecimal (loc);
143                                 return;
144                         } else if (left is EnumConstant || right is EnumConstant){
145                                 if (left is EnumConstant)
146                                         left = ((EnumConstant) left).Child;
147                                 if (right is EnumConstant)
148                                         right = ((EnumConstant) right).Child;
149
150                                 DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
151                                 return;
152
153                         } else {
154                                 //
155                                 // Force conversions to int32
156                                 //
157                                 if (!(left is IntConstant))
158                                         left = left.ToInt (loc);
159                                 if (!(right is IntConstant))
160                                         right = right.ToInt (loc);
161                         }
162                         return;
163                 }
164
165                 static void Error_CompileTimeOverflow (Location loc)
166                 {
167                         Report.Error (220, loc, "The operation overflows at compile time in checked mode");
168                 }
169                 
170                 /// <summary>
171                 ///   Constant expression folder for binary operations.
172                 ///
173                 ///   Returns null if the expression can not be folded.
174                 /// </summary>
175                 static public Expression BinaryFold (EmitContext ec, Binary.Operator oper,
176                                                      Constant left, Constant right, Location loc)
177                 {
178                         if (left is EmptyConstantCast)
179                                 return BinaryFold (ec, oper, ((EmptyConstantCast)left).child, right, loc);
180
181                         if (right is EmptyConstantCast)
182                                 return BinaryFold (ec, oper, left, ((EmptyConstantCast)right).child, loc);
183
184                         Type lt = left.Type;
185                         Type rt = right.Type;
186                         Type result_type = null;
187                         bool bool_res;
188
189                         //
190                         // Enumerator folding
191                         //
192                         if (rt == lt && left is EnumConstant)
193                                 result_type = lt;
194
195                         //
196                         // During an enum evaluation, we need to unwrap enumerations
197                         //
198                         if (ec.InEnumContext){
199                                 if (left is EnumConstant)
200                                         left = ((EnumConstant) left).Child;
201                                 
202                                 if (right is EnumConstant)
203                                         right = ((EnumConstant) right).Child;
204                         }
205
206                         if (left is BoolConstant && right is BoolConstant) {
207                                 bool lv = ((BoolConstant) left ).Value;
208                                 bool rv = ((BoolConstant) right).Value;
209                                 switch (oper) {
210                                 case Binary.Operator.BitwiseAnd:
211                                 case Binary.Operator.LogicalAnd:
212                                         return new BoolConstant (lv && rv, left.Location);
213                                 case Binary.Operator.BitwiseOr:
214                                 case Binary.Operator.LogicalOr:
215                                         return new BoolConstant (lv || rv, left.Location);
216                                 case Binary.Operator.ExclusiveOr:
217                                         return new BoolConstant (lv ^ rv, left.Location);
218                                 case Binary.Operator.Equality:
219                                         return new BoolConstant (lv == rv, left.Location);
220                                 case Binary.Operator.Inequality:
221                                         return new BoolConstant (lv != rv, left.Location);
222                                 default:
223                                         throw new InternalErrorException ("Invalid operator on booleans: " + oper);
224                                 }
225                         }
226
227                         Type wrap_as;
228                         Constant result = null;
229                         switch (oper){
230                         case Binary.Operator.BitwiseOr:
231                                 DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
232                                 if (left == null || right == null)
233                                         return null;
234
235                                 if (left is IntConstant){
236                                         IntConstant v;
237                                         int res = ((IntConstant) left).Value | ((IntConstant) right).Value;
238                                         
239                                         v = new IntConstant (res, left.Location);
240                                         if (result_type == null)
241                                                 return v;
242                                         else
243                                                 return new EnumConstant (v, result_type);
244                                 } else if (left is UIntConstant){
245                                         UIntConstant v;
246                                         uint res = ((UIntConstant)left).Value | ((UIntConstant)right).Value;
247                                         
248                                         v = new UIntConstant (res, left.Location);
249                                         if (result_type == null)
250                                                 return v;
251                                         else
252                                                 return new EnumConstant (v, result_type);
253                                 } else if (left is LongConstant){
254                                         LongConstant v;
255                                         long res = ((LongConstant)left).Value | ((LongConstant)right).Value;
256                                         
257                                         v = new LongConstant (res, left.Location);
258                                         if (result_type == null)
259                                                 return v;
260                                         else
261                                                 return new EnumConstant (v, result_type);
262                                 } else if (left is ULongConstant){
263                                         ULongConstant v;
264                                         ulong res = ((ULongConstant)left).Value |
265                                                 ((ULongConstant)right).Value;
266                                         
267                                         v = new ULongConstant (res, left.Location);
268                                         if (result_type == null)
269                                                 return v;
270                                         else
271                                                 return new EnumConstant (v, result_type);
272                                 } else if (left is UShortConstant){
273                                         UShortConstant v;
274                                         ushort res = (ushort) (((UShortConstant)left).Value |
275                                                                ((UShortConstant)right).Value);
276                                         
277                                         v = new UShortConstant (res, left.Location);
278                                         if (result_type == null)
279                                                 return v;
280                                         else
281                                                 return new EnumConstant (v, result_type);
282                                 } else if (left is ShortConstant){
283                                         ShortConstant v;
284                                         short res = (short) (((ShortConstant)left).Value |
285                                                              ((ShortConstant)right).Value);
286                                         
287                                         v = new ShortConstant (res, left.Location);
288                                         if (result_type == null)
289                                                 return v;
290                                         else
291                                                 return new EnumConstant (v, result_type);
292                                 }
293                                 break;
294                                 
295                         case Binary.Operator.BitwiseAnd:
296                                 DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
297                                 if (left == null || right == null)
298                                         return null;
299                                 
300                                 if (left is IntConstant){
301                                         IntConstant v;
302                                         int res = ((IntConstant) left).Value & ((IntConstant) right).Value;
303                                         
304                                         v = new IntConstant (res, left.Location);
305                                         if (result_type == null)
306                                                 return v;
307                                         else
308                                                 return new EnumConstant (v, result_type);
309                                 } else if (left is UIntConstant){
310                                         UIntConstant v;
311                                         uint res = ((UIntConstant)left).Value & ((UIntConstant)right).Value;
312                                         
313                                         v = new UIntConstant (res, left.Location);
314                                         if (result_type == null)
315                                                 return v;
316                                         else
317                                                 return new EnumConstant (v, result_type);
318                                 } else if (left is LongConstant){
319                                         LongConstant v;
320                                         long res = ((LongConstant)left).Value & ((LongConstant)right).Value;
321                                         
322                                         v = new LongConstant (res, left.Location);
323                                         if (result_type == null)
324                                                 return v;
325                                         else
326                                                 return new EnumConstant (v, result_type);
327                                 } else if (left is ULongConstant){
328                                         ULongConstant v;
329                                         ulong res = ((ULongConstant)left).Value &
330                                                 ((ULongConstant)right).Value;
331                                         
332                                         v = new ULongConstant (res, left.Location);
333                                         if (result_type == null)
334                                                 return v;
335                                         else
336                                                 return new EnumConstant (v, result_type);
337                                 } else if (left is UShortConstant){
338                                         UShortConstant v;
339                                         ushort res = (ushort) (((UShortConstant)left).Value &
340                                                                ((UShortConstant)right).Value);
341                                         
342                                         v = new UShortConstant (res, left.Location);
343                                         if (result_type == null)
344                                                 return v;
345                                         else
346                                                 return new EnumConstant (v, result_type);
347                                 } else if (left is ShortConstant){
348                                         ShortConstant v;
349                                         short res = (short) (((ShortConstant)left).Value &
350                                                              ((ShortConstant)right).Value);
351                                         
352                                         v = new ShortConstant (res, left.Location);
353                                         if (result_type == null)
354                                                 return v;
355                                         else
356                                                 return new EnumConstant (v, result_type);
357                                 }
358                                 break;
359
360                         case Binary.Operator.ExclusiveOr:
361                                 DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
362                                 if (left == null || right == null)
363                                         return null;
364                                 
365                                 if (left is IntConstant){
366                                         IntConstant v;
367                                         int res = ((IntConstant) left).Value ^ ((IntConstant) right).Value;
368                                         
369                                         v = new IntConstant (res, left.Location);
370                                         if (result_type == null)
371                                                 return v;
372                                         else
373                                                 return new EnumConstant (v, result_type);
374                                 } else if (left is UIntConstant){
375                                         UIntConstant v;
376                                         uint res = ((UIntConstant)left).Value ^ ((UIntConstant)right).Value;
377                                         
378                                         v = new UIntConstant (res, left.Location);
379                                         if (result_type == null)
380                                                 return v;
381                                         else
382                                                 return new EnumConstant (v, result_type);
383                                 } else if (left is LongConstant){
384                                         LongConstant v;
385                                         long res = ((LongConstant)left).Value ^ ((LongConstant)right).Value;
386                                         
387                                         v = new LongConstant (res, left.Location);
388                                         if (result_type == null)
389                                                 return v;
390                                         else
391                                                 return new EnumConstant (v, result_type);
392                                 } else if (left is ULongConstant){
393                                         ULongConstant v;
394                                         ulong res = ((ULongConstant)left).Value ^
395                                                 ((ULongConstant)right).Value;
396                                         
397                                         v = new ULongConstant (res, left.Location);
398                                         if (result_type == null)
399                                                 return v;
400                                         else
401                                                 return new EnumConstant (v, result_type);
402                                 } else if (left is UShortConstant){
403                                         UShortConstant v;
404                                         ushort res = (ushort) (((UShortConstant)left).Value ^
405                                                                ((UShortConstant)right).Value);
406                                         
407                                         v = new UShortConstant (res, left.Location);
408                                         if (result_type == null)
409                                                 return v;
410                                         else
411                                                 return new EnumConstant (v, result_type);
412                                 } else if (left is ShortConstant){
413                                         ShortConstant v;
414                                         short res = (short)(((ShortConstant)left).Value ^
415                                                             ((ShortConstant)right).Value);
416                                         
417                                         v = new ShortConstant (res, left.Location);
418                                         if (result_type == null)
419                                                 return v;
420                                         else
421                                                 return new EnumConstant (v, result_type);
422                                 }
423                                 break;
424
425                         case Binary.Operator.Addition:
426                                 bool left_is_string = left is StringConstant;
427                                 bool right_is_string = right is StringConstant;
428
429                                 //
430                                 // If both sides are strings, then concatenate, if
431                                 // one is a string, and the other is not, then defer
432                                 // to runtime concatenation
433                                 //
434                                 wrap_as = null;
435                                 if (left_is_string || right_is_string){
436                                         if (left_is_string && right_is_string)
437                                                 return new StringConstant (
438                                                         ((StringConstant) left).Value +
439                                                         ((StringConstant) right).Value, left.Location);
440                                         
441                                         return null;
442                                 }
443
444                                 //
445                                 // handle "E operator + (E x, U y)"
446                                 // handle "E operator + (Y y, E x)"
447                                 //
448                                 // note that E operator + (E x, E y) is invalid
449                                 //
450                                 if (left is EnumConstant){
451                                         if (right is EnumConstant){
452                                                 return null;
453                                         }
454
455                                         right = right.ToType (((EnumConstant) left).Child.Type);
456                                         if (right == null)
457                                                 return null;
458
459                                         wrap_as = left.Type;
460                                 } else if (right is EnumConstant){
461                                         left = left.ToType (((EnumConstant) right).Child.Type);
462                                         if (left == null)
463                                                 return null;
464
465                                         wrap_as = right.Type;
466                                 }
467
468                                 result = null;
469                                 DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
470                                 if (left == null || right == null)
471                                         return null;
472
473                                 try {
474                                         if (left is DoubleConstant){
475                                                 double res;
476                                                 
477                                                 if (ec.ConstantCheckState)
478                                                         res = checked (((DoubleConstant) left).Value +
479                                                                        ((DoubleConstant) right).Value);
480                                                 else
481                                                         res = unchecked (((DoubleConstant) left).Value +
482                                                                          ((DoubleConstant) right).Value);
483                                                 
484                                                 result = new DoubleConstant (res, left.Location);
485                                         } else if (left is FloatConstant){
486                                                 float res;
487                                                 
488                                                 if (ec.ConstantCheckState)
489                                                         res = checked (((FloatConstant) left).Value +
490                                                                        ((FloatConstant) right).Value);
491                                                 else
492                                                         res = unchecked (((FloatConstant) left).Value +
493                                                                          ((FloatConstant) right).Value);
494                                                 
495                                                 result = new FloatConstant (res, left.Location);
496                                         } else if (left is ULongConstant){
497                                                 ulong res;
498                                                 
499                                                 if (ec.ConstantCheckState)
500                                                         res = checked (((ULongConstant) left).Value +
501                                                                        ((ULongConstant) right).Value);
502                                                 else
503                                                         res = unchecked (((ULongConstant) left).Value +
504                                                                          ((ULongConstant) right).Value);
505
506                                                 result = new ULongConstant (res, left.Location);
507                                         } else if (left is LongConstant){
508                                                 long res;
509                                                 
510                                                 if (ec.ConstantCheckState)
511                                                         res = checked (((LongConstant) left).Value +
512                                                                        ((LongConstant) right).Value);
513                                                 else
514                                                         res = unchecked (((LongConstant) left).Value +
515                                                                          ((LongConstant) right).Value);
516                                                 
517                                                 result = new LongConstant (res, left.Location);
518                                         } else if (left is UIntConstant){
519                                                 uint res;
520                                                 
521                                                 if (ec.ConstantCheckState)
522                                                         res = checked (((UIntConstant) left).Value +
523                                                                        ((UIntConstant) right).Value);
524                                                 else
525                                                         res = unchecked (((UIntConstant) left).Value +
526                                                                          ((UIntConstant) right).Value);
527                                                 
528                                                 result = new UIntConstant (res, left.Location);
529                                         } else if (left is IntConstant){
530                                                 int res;
531
532                                                 if (ec.ConstantCheckState)
533                                                         res = checked (((IntConstant) left).Value +
534                                                                        ((IntConstant) right).Value);
535                                                 else
536                                                         res = unchecked (((IntConstant) left).Value +
537                                                                          ((IntConstant) right).Value);
538
539                                                 result = new IntConstant (res, left.Location);
540                                         } else if (left is DecimalConstant) {
541                                                 decimal res;
542
543                                                 if (ec.ConstantCheckState)
544                                                         res = checked (((DecimalConstant) left).Value +
545                                                                 ((DecimalConstant) right).Value);
546                                                 else
547                                                         res = unchecked (((DecimalConstant) left).Value +
548                                                                 ((DecimalConstant) right).Value);
549
550                                                 result = new DecimalConstant (res, left.Location);
551                                         } else {
552                                                 throw new Exception ( "Unexepected addition input: " + left);
553                                         }
554                                 } catch (OverflowException){
555                                         Error_CompileTimeOverflow (loc);
556                                 }
557
558                                 if (wrap_as != null) {
559                                         try {
560                                                 return result.TryReduce (ec, wrap_as, loc);
561                                         }
562                                         catch (OverflowException) {
563                                                 return null;
564                                         }
565                                 }
566                                 else
567                                         return result;
568
569                         case Binary.Operator.Subtraction:
570                                 //
571                                 // handle "E operator - (E x, U y)"
572                                 // handle "E operator - (Y y, E x)"
573                                 // handle "U operator - (E x, E y)"
574                                 //
575                                 wrap_as = null;
576                                 if (left is EnumConstant){
577                                         if (right is EnumConstant){
578                                                 if (left.Type != right.Type) {
579                                                         Binary.Error_OperatorCannotBeApplied (loc, "-", left.Type, right.Type);
580                                                         return null;
581                                                 }
582
583                                                 wrap_as = TypeManager.EnumToUnderlying (left.Type);
584                                                 right = ((EnumConstant) right).Child.ToType (wrap_as);
585                                                 if (right == null)
586                                                         return null;
587
588                                                 left = ((EnumConstant) left).Child.ToType (wrap_as);
589                                                 if (left == null)
590                                                         return null;
591                                         }
592                                         else {
593                                                 right = right.ToType (((EnumConstant) left).Child.Type);
594                                                 if (right == null)
595                                                         return null;
596
597                                                 wrap_as = left.Type;
598                                         }
599                                 } else if (right is EnumConstant){
600                                         left = left.ToType (((EnumConstant) right).Child.Type);
601                                         if (left == null)
602                                                 return null;
603
604                                         wrap_as = right.Type;
605                                 }
606
607                                 DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
608                                 if (left == null || right == null)
609                                         return null;
610
611                                 try {
612                                         if (left is DoubleConstant){
613                                                 double res;
614                                                 
615                                                 if (ec.ConstantCheckState)
616                                                         res = checked (((DoubleConstant) left).Value -
617                                                                        ((DoubleConstant) right).Value);
618                                                 else
619                                                         res = unchecked (((DoubleConstant) left).Value -
620                                                                          ((DoubleConstant) right).Value);
621                                                 
622                                                 result = new DoubleConstant (res, left.Location);
623                                         } else if (left is FloatConstant){
624                                                 float res;
625                                                 
626                                                 if (ec.ConstantCheckState)
627                                                         res = checked (((FloatConstant) left).Value -
628                                                                        ((FloatConstant) right).Value);
629                                                 else
630                                                         res = unchecked (((FloatConstant) left).Value -
631                                                                          ((FloatConstant) right).Value);
632                                                 
633                                                 result = new FloatConstant (res, left.Location);
634                                         } else if (left is ULongConstant){
635                                                 ulong res;
636                                                 
637                                                 if (ec.ConstantCheckState)
638                                                         res = checked (((ULongConstant) left).Value -
639                                                                        ((ULongConstant) right).Value);
640                                                 else
641                                                         res = unchecked (((ULongConstant) left).Value -
642                                                                          ((ULongConstant) right).Value);
643                                                 
644                                                 result = new ULongConstant (res, left.Location);
645                                         } else if (left is LongConstant){
646                                                 long res;
647                                                 
648                                                 if (ec.ConstantCheckState)
649                                                         res = checked (((LongConstant) left).Value -
650                                                                        ((LongConstant) right).Value);
651                                                 else
652                                                         res = unchecked (((LongConstant) left).Value -
653                                                                          ((LongConstant) right).Value);
654                                                 
655                                                 result = new LongConstant (res, left.Location);
656                                         } else if (left is UIntConstant){
657                                                 uint res;
658                                                 
659                                                 if (ec.ConstantCheckState)
660                                                         res = checked (((UIntConstant) left).Value -
661                                                                        ((UIntConstant) right).Value);
662                                                 else
663                                                         res = unchecked (((UIntConstant) left).Value -
664                                                                          ((UIntConstant) right).Value);
665                                                 
666                                                 result = new UIntConstant (res, left.Location);
667                                         } else if (left is IntConstant){
668                                                 int res;
669
670                                                 if (ec.ConstantCheckState)
671                                                         res = checked (((IntConstant) left).Value -
672                                                                        ((IntConstant) right).Value);
673                                                 else
674                                                         res = unchecked (((IntConstant) left).Value -
675                                                                          ((IntConstant) right).Value);
676
677                                                 result = new IntConstant (res, left.Location);
678                                         } else if (left is DecimalConstant) {
679                                                 decimal res;
680
681                                                 if (ec.ConstantCheckState)
682                                                         res = checked (((DecimalConstant) left).Value -
683                                                                 ((DecimalConstant) right).Value);
684                                                 else
685                                                         res = unchecked (((DecimalConstant) left).Value -
686                                                                 ((DecimalConstant) right).Value);
687
688                                                 return new DecimalConstant (res, left.Location);
689                                         } else {
690                                                 throw new Exception ( "Unexepected subtraction input: " + left);
691                                         }
692                                 } catch (OverflowException){
693                                         Error_CompileTimeOverflow (loc);
694                                 }
695
696                                 if (wrap_as != null) {
697                                         try {
698                                                 return result.TryReduce (ec, wrap_as, loc);
699                                         }
700                                         catch (OverflowException) {
701                                                 return null;
702                                         }
703                                 }
704
705                                 return result;
706                                 
707                         case Binary.Operator.Multiply:
708                                 DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
709                                 if (left == null || right == null)
710                                         return null;
711
712                                 try {
713                                         if (left is DoubleConstant){
714                                                 double res;
715                                                 
716                                                 if (ec.ConstantCheckState)
717                                                         res = checked (((DoubleConstant) left).Value *
718                                                                 ((DoubleConstant) right).Value);
719                                                 else
720                                                         res = unchecked (((DoubleConstant) left).Value *
721                                                                 ((DoubleConstant) right).Value);
722                                                 
723                                                 return new DoubleConstant (res, left.Location);
724                                         } else if (left is FloatConstant){
725                                                 float res;
726                                                 
727                                                 if (ec.ConstantCheckState)
728                                                         res = checked (((FloatConstant) left).Value *
729                                                                 ((FloatConstant) right).Value);
730                                                 else
731                                                         res = unchecked (((FloatConstant) left).Value *
732                                                                 ((FloatConstant) right).Value);
733                                                 
734                                                 return new FloatConstant (res, left.Location);
735                                         } else if (left is ULongConstant){
736                                                 ulong res;
737                                                 
738                                                 if (ec.ConstantCheckState)
739                                                         res = checked (((ULongConstant) left).Value *
740                                                                 ((ULongConstant) right).Value);
741                                                 else
742                                                         res = unchecked (((ULongConstant) left).Value *
743                                                                 ((ULongConstant) right).Value);
744                                                 
745                                                 return new ULongConstant (res, left.Location);
746                                         } else if (left is LongConstant){
747                                                 long res;
748                                                 
749                                                 if (ec.ConstantCheckState)
750                                                         res = checked (((LongConstant) left).Value *
751                                                                 ((LongConstant) right).Value);
752                                                 else
753                                                         res = unchecked (((LongConstant) left).Value *
754                                                                 ((LongConstant) right).Value);
755                                                 
756                                                 return new LongConstant (res, left.Location);
757                                         } else if (left is UIntConstant){
758                                                 uint res;
759                                                 
760                                                 if (ec.ConstantCheckState)
761                                                         res = checked (((UIntConstant) left).Value *
762                                                                 ((UIntConstant) right).Value);
763                                                 else
764                                                         res = unchecked (((UIntConstant) left).Value *
765                                                                 ((UIntConstant) right).Value);
766                                                 
767                                                 return new UIntConstant (res, left.Location);
768                                         } else if (left is IntConstant){
769                                                 int res;
770
771                                                 if (ec.ConstantCheckState)
772                                                         res = checked (((IntConstant) left).Value *
773                                                                 ((IntConstant) right).Value);
774                                                 else
775                                                         res = unchecked (((IntConstant) left).Value *
776                                                                 ((IntConstant) right).Value);
777
778                                                 return new IntConstant (res, left.Location);
779                                         } else if (left is DecimalConstant) {
780                                                 decimal res;
781
782                                                 if (ec.ConstantCheckState)
783                                                         res = checked (((DecimalConstant) left).Value *
784                                                                 ((DecimalConstant) right).Value);
785                                                 else
786                                                         res = unchecked (((DecimalConstant) left).Value *
787                                                                 ((DecimalConstant) right).Value);
788
789                                                 return new DecimalConstant (res, left.Location);
790                                         } else {
791                                                 throw new Exception ( "Unexepected multiply input: " + left);
792                                         }
793                                 } catch (OverflowException){
794                                         Error_CompileTimeOverflow (loc);
795                                 }
796                                 break;
797
798                         case Binary.Operator.Division:
799                                 DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
800                                 if (left == null || right == null)
801                                         return null;
802
803                                 try {
804                                         if (left is DoubleConstant){
805                                                 double res;
806                                                 
807                                                 if (ec.ConstantCheckState)
808                                                         res = checked (((DoubleConstant) left).Value /
809                                                                 ((DoubleConstant) right).Value);
810                                                 else
811                                                         res = unchecked (((DoubleConstant) left).Value /
812                                                                 ((DoubleConstant) right).Value);
813                                                 
814                                                 return new DoubleConstant (res, left.Location);
815                                         } else if (left is FloatConstant){
816                                                 float res;
817                                                 
818                                                 if (ec.ConstantCheckState)
819                                                         res = checked (((FloatConstant) left).Value /
820                                                                 ((FloatConstant) right).Value);
821                                                 else
822                                                         res = unchecked (((FloatConstant) left).Value /
823                                                                 ((FloatConstant) right).Value);
824                                                 
825                                                 return new FloatConstant (res, left.Location);
826                                         } else if (left is ULongConstant){
827                                                 ulong res;
828                                                 
829                                                 if (ec.ConstantCheckState)
830                                                         res = checked (((ULongConstant) left).Value /
831                                                                 ((ULongConstant) right).Value);
832                                                 else
833                                                         res = unchecked (((ULongConstant) left).Value /
834                                                                 ((ULongConstant) right).Value);
835                                                 
836                                                 return new ULongConstant (res, left.Location);
837                                         } else if (left is LongConstant){
838                                                 long res;
839                                                 
840                                                 if (ec.ConstantCheckState)
841                                                         res = checked (((LongConstant) left).Value /
842                                                                 ((LongConstant) right).Value);
843                                                 else
844                                                         res = unchecked (((LongConstant) left).Value /
845                                                                 ((LongConstant) right).Value);
846                                                 
847                                                 return new LongConstant (res, left.Location);
848                                         } else if (left is UIntConstant){
849                                                 uint res;
850                                                 
851                                                 if (ec.ConstantCheckState)
852                                                         res = checked (((UIntConstant) left).Value /
853                                                                 ((UIntConstant) right).Value);
854                                                 else
855                                                         res = unchecked (((UIntConstant) left).Value /
856                                                                 ((UIntConstant) right).Value);
857                                                 
858                                                 return new UIntConstant (res, left.Location);
859                                         } else if (left is IntConstant){
860                                                 int res;
861
862                                                 if (ec.ConstantCheckState)
863                                                         res = checked (((IntConstant) left).Value /
864                                                                 ((IntConstant) right).Value);
865                                                 else
866                                                         res = unchecked (((IntConstant) left).Value /
867                                                                 ((IntConstant) right).Value);
868
869                                                 return new IntConstant (res, left.Location);
870                                         } else if (left is DecimalConstant) {
871                                                 decimal res;
872
873                                                 if (ec.ConstantCheckState)
874                                                         res = checked (((DecimalConstant) left).Value /
875                                                                 ((DecimalConstant) right).Value);
876                                                 else
877                                                         res = unchecked (((DecimalConstant) left).Value /
878                                                                 ((DecimalConstant) right).Value);
879
880                                                 return new DecimalConstant (res, left.Location);
881                                         } else {
882                                                 throw new Exception ( "Unexepected division input: " + left);
883                                         }
884                                 } catch (OverflowException){
885                                         Error_CompileTimeOverflow (loc);
886
887                                 } catch (DivideByZeroException) {
888                                         Report.Error (020, loc, "Division by constant zero");
889                                 }
890                                 
891                                 break;
892                                 
893                         case Binary.Operator.Modulus:
894                                 DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
895                                 if (left == null || right == null)
896                                         return null;
897
898                                 try {
899                                         if (left is DoubleConstant){
900                                                 double res;
901                                                 
902                                                 if (ec.ConstantCheckState)
903                                                         res = checked (((DoubleConstant) left).Value %
904                                                                        ((DoubleConstant) right).Value);
905                                                 else
906                                                         res = unchecked (((DoubleConstant) left).Value %
907                                                                          ((DoubleConstant) right).Value);
908                                                 
909                                                 return new DoubleConstant (res, left.Location);
910                                         } else if (left is FloatConstant){
911                                                 float res;
912                                                 
913                                                 if (ec.ConstantCheckState)
914                                                         res = checked (((FloatConstant) left).Value %
915                                                                        ((FloatConstant) right).Value);
916                                                 else
917                                                         res = unchecked (((FloatConstant) left).Value %
918                                                                          ((FloatConstant) right).Value);
919                                                 
920                                                 return new FloatConstant (res, left.Location);
921                                         } else if (left is ULongConstant){
922                                                 ulong res;
923                                                 
924                                                 if (ec.ConstantCheckState)
925                                                         res = checked (((ULongConstant) left).Value %
926                                                                        ((ULongConstant) right).Value);
927                                                 else
928                                                         res = unchecked (((ULongConstant) left).Value %
929                                                                          ((ULongConstant) right).Value);
930                                                 
931                                                 return new ULongConstant (res, left.Location);
932                                         } else if (left is LongConstant){
933                                                 long res;
934                                                 
935                                                 if (ec.ConstantCheckState)
936                                                         res = checked (((LongConstant) left).Value %
937                                                                        ((LongConstant) right).Value);
938                                                 else
939                                                         res = unchecked (((LongConstant) left).Value %
940                                                                          ((LongConstant) right).Value);
941                                                 
942                                                 return new LongConstant (res, left.Location);
943                                         } else if (left is UIntConstant){
944                                                 uint res;
945                                                 
946                                                 if (ec.ConstantCheckState)
947                                                         res = checked (((UIntConstant) left).Value %
948                                                                        ((UIntConstant) right).Value);
949                                                 else
950                                                         res = unchecked (((UIntConstant) left).Value %
951                                                                          ((UIntConstant) right).Value);
952                                                 
953                                                 return new UIntConstant (res, left.Location);
954                                         } else if (left is IntConstant){
955                                                 int res;
956
957                                                 if (ec.ConstantCheckState)
958                                                         res = checked (((IntConstant) left).Value %
959                                                                        ((IntConstant) right).Value);
960                                                 else
961                                                         res = unchecked (((IntConstant) left).Value %
962                                                                          ((IntConstant) right).Value);
963
964                                                 return new IntConstant (res, left.Location);
965                                         } else {
966                                                 throw new Exception ( "Unexepected modulus input: " + left);
967                                         }
968                                 } catch (DivideByZeroException){
969                                         Report.Error (020, loc, "Division by constant zero");
970                                 } catch (OverflowException){
971                                         Error_CompileTimeOverflow (loc);
972                                 }
973                                 break;
974
975                                 //
976                                 // There is no overflow checking on left shift
977                                 //
978                         case Binary.Operator.LeftShift:
979                                 IntConstant ic = right.ToInt (loc);
980                                 if (ic == null){
981                                         Binary.Error_OperatorCannotBeApplied (loc, "<<", lt, rt);
982                                         return null;
983                                 }
984                                 int lshift_val = ic.Value;
985
986                                 IntConstant lic;
987                                 if ((lic = left.ConvertToInt ()) != null)
988                                         return new IntConstant (lic.Value << lshift_val, left.Location);
989
990                                 UIntConstant luic;
991                                 if ((luic = left.ConvertToUInt ()) != null)
992                                         return new UIntConstant (luic.Value << lshift_val, left.Location);
993
994                                 LongConstant llc;
995                                 if ((llc = left.ConvertToLong ()) != null)
996                                         return new LongConstant (llc.Value << lshift_val, left.Location);
997
998                                 ULongConstant lulc;
999                                 if ((lulc = left.ConvertToULong ()) != null)
1000                                         return new ULongConstant (lulc.Value << lshift_val, left.Location);
1001
1002                                 Binary.Error_OperatorCannotBeApplied (loc, "<<", lt, rt);
1003                                 break;
1004
1005                                 //
1006                                 // There is no overflow checking on right shift
1007                                 //
1008                         case Binary.Operator.RightShift:
1009                                 IntConstant sic = right.ToInt (loc);
1010                                 if (sic == null){
1011                                         Binary.Error_OperatorCannotBeApplied (loc, ">>", lt, rt);
1012                                         return null;
1013                                 }
1014                                 int rshift_val = sic.Value;
1015
1016                                 IntConstant ric;
1017                                 if ((ric = left.ConvertToInt ()) != null)
1018                                         return new IntConstant (ric.Value >> rshift_val, left.Location);
1019
1020                                 UIntConstant ruic;
1021                                 if ((ruic = left.ConvertToUInt ()) != null)
1022                                         return new UIntConstant (ruic.Value >> rshift_val, left.Location);
1023
1024                                 LongConstant rlc;
1025                                 if ((rlc = left.ConvertToLong ()) != null)
1026                                         return new LongConstant (rlc.Value >> rshift_val, left.Location);
1027
1028                                 ULongConstant rulc;
1029                                 if ((rulc = left.ConvertToULong ()) != null)
1030                                         return new ULongConstant (rulc.Value >> rshift_val, left.Location);
1031
1032                                 Binary.Error_OperatorCannotBeApplied (loc, ">>", lt, rt);
1033                                 break;
1034
1035                         case Binary.Operator.Equality:
1036                                 if (left is NullConstant){
1037                                         if (right is NullConstant)
1038                                                 return new BoolConstant (true, left.Location);
1039                                         else if (right is StringConstant)
1040                                                 return new BoolConstant (
1041                                                         ((StringConstant) right).Value == null, left.Location);
1042                                 } else if (right is NullConstant){
1043                                         if (left is NullConstant)
1044                                                 return new BoolConstant (true, left.Location);
1045                                         else if (left is StringConstant)
1046                                                 return new BoolConstant (
1047                                                         ((StringConstant) left).Value == null, left.Location);
1048                                 }
1049                                 if (left is StringConstant && right is StringConstant){
1050                                         return new BoolConstant (
1051                                                 ((StringConstant) left).Value ==
1052                                                 ((StringConstant) right).Value, left.Location);
1053                                         
1054                                 }
1055
1056                                 DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
1057                                 if (left == null || right == null)
1058                                         return null;
1059
1060                                 bool_res = false;
1061                                 if (left is DoubleConstant)
1062                                         bool_res = ((DoubleConstant) left).Value ==
1063                                                 ((DoubleConstant) right).Value;
1064                                 else if (left is FloatConstant)
1065                                         bool_res = ((FloatConstant) left).Value ==
1066                                                 ((FloatConstant) right).Value;
1067                                 else if (left is ULongConstant)
1068                                         bool_res = ((ULongConstant) left).Value ==
1069                                                 ((ULongConstant) right).Value;
1070                                 else if (left is LongConstant)
1071                                         bool_res = ((LongConstant) left).Value ==
1072                                                 ((LongConstant) right).Value;
1073                                 else if (left is UIntConstant)
1074                                         bool_res = ((UIntConstant) left).Value ==
1075                                                 ((UIntConstant) right).Value;
1076                                 else if (left is IntConstant)
1077                                         bool_res = ((IntConstant) left).Value ==
1078                                                 ((IntConstant) right).Value;
1079                                 else
1080                                         return null;
1081
1082                                 return new BoolConstant (bool_res, left.Location);
1083
1084                         case Binary.Operator.Inequality:
1085                                 if (left is NullConstant){
1086                                         if (right is NullConstant)
1087                                                 return new BoolConstant (false, left.Location);
1088                                         else if (right is StringConstant)
1089                                                 return new BoolConstant (
1090                                                         ((StringConstant) right).Value != null, left.Location);
1091                                 } else if (right is NullConstant){
1092                                         if (left is NullConstant)
1093                                                 return new BoolConstant (false, left.Location);
1094                                         else if (left is StringConstant)
1095                                                 return new BoolConstant (
1096                                                         ((StringConstant) left).Value != null, left.Location);
1097                                 }
1098                                 if (left is StringConstant && right is StringConstant){
1099                                         return new BoolConstant (
1100                                                 ((StringConstant) left).Value !=
1101                                                 ((StringConstant) right).Value, left.Location);
1102                                         
1103                                 }
1104                                 DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
1105                                 if (left == null || right == null)
1106                                         return null;
1107
1108                                 bool_res = false;
1109                                 if (left is DoubleConstant)
1110                                         bool_res = ((DoubleConstant) left).Value !=
1111                                                 ((DoubleConstant) right).Value;
1112                                 else if (left is FloatConstant)
1113                                         bool_res = ((FloatConstant) left).Value !=
1114                                                 ((FloatConstant) right).Value;
1115                                 else if (left is ULongConstant)
1116                                         bool_res = ((ULongConstant) left).Value !=
1117                                                 ((ULongConstant) right).Value;
1118                                 else if (left is LongConstant)
1119                                         bool_res = ((LongConstant) left).Value !=
1120                                                 ((LongConstant) right).Value;
1121                                 else if (left is UIntConstant)
1122                                         bool_res = ((UIntConstant) left).Value !=
1123                                                 ((UIntConstant) right).Value;
1124                                 else if (left is IntConstant)
1125                                         bool_res = ((IntConstant) left).Value !=
1126                                                 ((IntConstant) right).Value;
1127                                 else
1128                                         return null;
1129
1130                                 return new BoolConstant (bool_res, left.Location);
1131
1132                         case Binary.Operator.LessThan:
1133                                 DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
1134                                 if (left == null || right == null)
1135                                         return null;
1136
1137                                 bool_res = false;
1138                                 if (left is DoubleConstant)
1139                                         bool_res = ((DoubleConstant) left).Value <
1140                                                 ((DoubleConstant) right).Value;
1141                                 else if (left is FloatConstant)
1142                                         bool_res = ((FloatConstant) left).Value <
1143                                                 ((FloatConstant) right).Value;
1144                                 else if (left is ULongConstant)
1145                                         bool_res = ((ULongConstant) left).Value <
1146                                                 ((ULongConstant) right).Value;
1147                                 else if (left is LongConstant)
1148                                         bool_res = ((LongConstant) left).Value <
1149                                                 ((LongConstant) right).Value;
1150                                 else if (left is UIntConstant)
1151                                         bool_res = ((UIntConstant) left).Value <
1152                                                 ((UIntConstant) right).Value;
1153                                 else if (left is IntConstant)
1154                                         bool_res = ((IntConstant) left).Value <
1155                                                 ((IntConstant) right).Value;
1156                                 else
1157                                         return null;
1158
1159                                 return new BoolConstant (bool_res, left.Location);
1160                                 
1161                         case Binary.Operator.GreaterThan:
1162                                 DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
1163                                 if (left == null || right == null)
1164                                         return null;
1165
1166                                 bool_res = false;
1167                                 if (left is DoubleConstant)
1168                                         bool_res = ((DoubleConstant) left).Value >
1169                                                 ((DoubleConstant) right).Value;
1170                                 else if (left is FloatConstant)
1171                                         bool_res = ((FloatConstant) left).Value >
1172                                                 ((FloatConstant) right).Value;
1173                                 else if (left is ULongConstant)
1174                                         bool_res = ((ULongConstant) left).Value >
1175                                                 ((ULongConstant) right).Value;
1176                                 else if (left is LongConstant)
1177                                         bool_res = ((LongConstant) left).Value >
1178                                                 ((LongConstant) right).Value;
1179                                 else if (left is UIntConstant)
1180                                         bool_res = ((UIntConstant) left).Value >
1181                                                 ((UIntConstant) right).Value;
1182                                 else if (left is IntConstant)
1183                                         bool_res = ((IntConstant) left).Value >
1184                                                 ((IntConstant) right).Value;
1185                                 else
1186                                         return null;
1187
1188                                 return new BoolConstant (bool_res, left.Location);
1189
1190                         case Binary.Operator.GreaterThanOrEqual:
1191                                 DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
1192                                 if (left == null || right == null)
1193                                         return null;
1194
1195                                 bool_res = false;
1196                                 if (left is DoubleConstant)
1197                                         bool_res = ((DoubleConstant) left).Value >=
1198                                                 ((DoubleConstant) right).Value;
1199                                 else if (left is FloatConstant)
1200                                         bool_res = ((FloatConstant) left).Value >=
1201                                                 ((FloatConstant) right).Value;
1202                                 else if (left is ULongConstant)
1203                                         bool_res = ((ULongConstant) left).Value >=
1204                                                 ((ULongConstant) right).Value;
1205                                 else if (left is LongConstant)
1206                                         bool_res = ((LongConstant) left).Value >=
1207                                                 ((LongConstant) right).Value;
1208                                 else if (left is UIntConstant)
1209                                         bool_res = ((UIntConstant) left).Value >=
1210                                                 ((UIntConstant) right).Value;
1211                                 else if (left is IntConstant)
1212                                         bool_res = ((IntConstant) left).Value >=
1213                                                 ((IntConstant) right).Value;
1214                                 else
1215                                         return null;
1216
1217                                 return new BoolConstant (bool_res, left.Location);
1218
1219                         case Binary.Operator.LessThanOrEqual:
1220                                 DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
1221                                 if (left == null || right == null)
1222                                         return null;
1223
1224                                 bool_res = false;
1225                                 if (left is DoubleConstant)
1226                                         bool_res = ((DoubleConstant) left).Value <=
1227                                                 ((DoubleConstant) right).Value;
1228                                 else if (left is FloatConstant)
1229                                         bool_res = ((FloatConstant) left).Value <=
1230                                                 ((FloatConstant) right).Value;
1231                                 else if (left is ULongConstant)
1232                                         bool_res = ((ULongConstant) left).Value <=
1233                                                 ((ULongConstant) right).Value;
1234                                 else if (left is LongConstant)
1235                                         bool_res = ((LongConstant) left).Value <=
1236                                                 ((LongConstant) right).Value;
1237                                 else if (left is UIntConstant)
1238                                         bool_res = ((UIntConstant) left).Value <=
1239                                                 ((UIntConstant) right).Value;
1240                                 else if (left is IntConstant)
1241                                         bool_res = ((IntConstant) left).Value <=
1242                                                 ((IntConstant) right).Value;
1243                                 else
1244                                         return null;
1245
1246                                 return new BoolConstant (bool_res, left.Location);
1247                         }
1248                                         
1249                         return null;
1250                 }
1251         }
1252 }