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