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