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