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