2007-01-16 Marek Safar <marek.safar@gmail.com>
[mono.git] / mcs / mcs / constant.cs
1 //
2 // constant.cs: Constants.
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //   Marek Safar (marek.safar@seznam.cz)
7 //
8 // (C) 2001 Ximian, Inc.
9 //
10 //
11
12 namespace Mono.CSharp {
13
14         using System;
15         using System.Reflection.Emit;
16
17         /// <summary>
18         ///   Base class for constants and literals.
19         /// </summary>
20         public abstract class Constant : Expression {
21
22                 protected Constant (Location loc)
23                 {
24                         this.loc = loc;
25                 }
26
27                 /// <remarks>
28                 ///   This is different from ToString in that ToString
29                 ///   is supposed to be there for debugging purposes,
30                 ///   and is not guaranteed to be useful for anything else,
31                 ///   AsString() will provide something that can be used
32                 ///   for round-tripping C# code.  Maybe it can be used
33                 ///   for IL assembly as well.
34                 /// </remarks>
35                 public abstract string AsString ();
36
37                 override public string ToString ()
38                 {
39                         return this.GetType ().Name + " (" + AsString () + ")";
40                 }
41
42                 public override bool GetAttributableValue (Type valueType, out object value)
43                 {
44                         if (valueType == TypeManager.object_type) {
45                                 value = GetTypedValue ();
46                                 return true;
47                         }
48
49                         Constant c = ImplicitConversionRequired (valueType, loc);
50                         if (c == null) {
51                                 value = null;
52                                 return false;
53                         }
54
55                         value = c.GetTypedValue ();
56                         return true;
57                 }
58
59                 /// <summary>
60                 ///  This is used to obtain the actual value of the literal
61                 ///  cast into an object.
62                 /// </summary>
63                 public abstract object GetValue ();
64
65                 public virtual object GetTypedValue ()
66                 {
67                         return GetValue ();
68                 }
69
70                 /// <summary>
71                 ///   Constants are always born in a fully resolved state
72                 /// </summary>
73                 public override Expression DoResolve (EmitContext ec)
74                 {
75                         return this;
76                 }
77
78                 public Constant ImplicitConversionRequired (Type type, Location loc)
79                 {
80                         Constant c = ConvertImplicitly (type);
81                         if (c == null)
82                                 Error_ValueCannotBeConverted (null, loc, type, false);
83                         return c;
84                 }
85
86                 public virtual Constant ConvertImplicitly (Type type)
87                 {
88                         if (this.type == type)
89                                 return this;
90
91                         if (Convert.ImplicitNumericConversion (this, type) == null) 
92                                 return null;
93
94                         bool fail;                      
95                         object constant_value = TypeManager.ChangeType (GetValue (), type, out fail);
96                         if (fail){
97                                 //
98                                 // We should always catch the error before this is ever
99                                 // reached, by calling Convert.ImplicitStandardConversionExists
100                                 //
101                                 throw new Exception (
102                                         String.Format ("LookupConstantValue: This should never be reached {0} {1}", Type, type));
103                         }
104
105                         return CreateConstant (type, constant_value, loc);
106                 }
107
108                 ///  Returns a constant instance based on Type
109                 ///  The returned value is already resolved.
110                 public static Constant CreateConstant (Type t, object v, Location loc)
111                 {
112                         if (t == TypeManager.int32_type)
113                                 return new IntConstant ((int) v, loc);
114                         if (t == TypeManager.string_type)
115                                 return new StringConstant ((string) v, loc);
116                         if (t == TypeManager.uint32_type)
117                                 return new UIntConstant ((uint) v, loc);
118                         if (t == TypeManager.int64_type)
119                                 return new LongConstant ((long) v, loc);
120                         if (t == TypeManager.uint64_type)
121                                 return new ULongConstant ((ulong) v, loc);
122                         if (t == TypeManager.float_type)
123                                 return new FloatConstant ((float) v, loc);
124                         if (t == TypeManager.double_type)
125                                 return new DoubleConstant ((double) v, loc);
126                         if (t == TypeManager.short_type)
127                                 return new ShortConstant ((short)v, loc);
128                         if (t == TypeManager.ushort_type)
129                                 return new UShortConstant ((ushort)v, loc);
130                         if (t == TypeManager.sbyte_type)
131                                 return new SByteConstant ((sbyte)v, loc);
132                         if (t == TypeManager.byte_type)
133                                 return new ByteConstant ((byte)v, loc);
134                         if (t == TypeManager.char_type)
135                                 return new CharConstant ((char)v, loc);
136                         if (t == TypeManager.bool_type)
137                                 return new BoolConstant ((bool) v, loc);
138                         if (t == TypeManager.decimal_type)
139                                 return new DecimalConstant ((decimal) v, loc);
140                         if (TypeManager.IsEnumType (t)) {
141                                 Type real_type = TypeManager.TypeToCoreType (v.GetType ());
142                                 if (real_type == t)
143                                         real_type = System.Enum.GetUnderlyingType (real_type);
144                                 return new EnumConstant (CreateConstant (real_type, v, loc), t);
145                         } 
146                         if (v == null && !TypeManager.IsValueType (t))
147                                 return new EmptyConstantCast (new NullConstant (loc), t);
148
149                         throw new Exception ("Unknown type for constant (" + t +
150                                         "), details: " + v);
151                 }
152
153                 protected static void CheckRange (bool inCheckedContext, ulong value, ulong max)
154                 {
155                         if (!inCheckedContext)
156                                 return;
157
158                         if (value > max)
159                                 throw new OverflowException ();
160                 }
161
162                 protected static void CheckRange (bool inCheckedContext, double value, long min, long max)
163                 {
164                         if (!inCheckedContext)
165                                 return;
166
167                         if (((value < min) || (value > max)))
168                                 throw new OverflowException ();
169
170                         if (double.IsNaN (value))
171                                 throw new OverflowException ();
172                 }
173
174                 protected static void CheckRange (bool inCheckedContext, double value, ulong min, ulong max)
175                 {
176                         if (!inCheckedContext)
177                                 return;
178
179                         if (((value < min) || (value > max)))
180                                 throw new OverflowException ();
181
182                         if (double.IsNaN (value))
183                                 throw new OverflowException ();
184                 }
185
186                 protected static void CheckUnsigned (bool inCheckedContext, long value)
187                 {
188                         if (!inCheckedContext)
189                                 return;
190
191                         if (value < 0)
192                                 throw new OverflowException ();
193                 }
194
195                 /// <summary>
196                 /// Maybe ConvertTo name is better. It tries to convert `this' constant to target_type.
197                 /// It throws OverflowException 
198                 /// </summary>
199                 // DON'T CALL THIS METHOD DIRECTLY AS IT DOES NOT HANDLE ENUMS
200                 public abstract Constant ConvertExplicitly (bool inCheckedContext, Type target_type);
201
202                 /// <summary>
203                 ///   Attempts to do a compile-time folding of a constant cast.
204                 /// </summary>
205                 public Constant TryReduce (EmitContext ec, Type target_type, Location loc)
206                 {
207                         try {
208                                 return TryReduce (ec, target_type);
209                         }
210                         catch (OverflowException) {
211                                 Report.Error (221, loc, "Constant value `{0}' cannot be converted to a `{1}' (use `unchecked' syntax to override)",
212                                         GetValue ().ToString (), TypeManager.CSharpName (target_type));
213                                 return null;
214                         }
215                 }
216
217                 Constant TryReduce (EmitContext ec, Type target_type)
218                 {
219                         if (Type == target_type)
220                                 return this;
221
222                         if (TypeManager.IsEnumType (target_type)) {
223                                 Constant c = TryReduce (ec, TypeManager.EnumToUnderlying (target_type));
224                                 if (c == null)
225                                         return null;
226
227                                 return new EnumConstant (c, target_type);
228                         }
229
230                         return ConvertExplicitly (ec.ConstantCheckState, target_type);
231                 }
232
233                 public abstract Constant Increment ();
234                 
235                 /// <summary>
236                 /// Need to pass type as the constant can require a boxing
237                 /// and in such case no optimization is possible
238                 /// </summary>
239                 public bool IsDefaultInitializer (Type type)
240                 {
241                         if (type == Type)
242                                 return IsDefaultValue;
243
244                         return Type == TypeManager.null_type;
245                 }
246
247                 public abstract bool IsDefaultValue {
248                         get;
249                 }
250
251                 public abstract bool IsNegative {
252                         get;
253                 }
254
255                 //
256                 // Returns true iff 1) the stack type of this is one of Object, 
257                 // int32, int64 and 2) this == 0 or this == null.
258                 //
259                 public virtual bool IsZeroInteger {
260                         get { return false; }
261                 }
262         }
263
264         public abstract class IntegralConstant : Constant {
265                 protected IntegralConstant (Location loc) :
266                         base (loc)
267                 {
268                 }
269
270                 public override void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
271                 {
272                         try {
273                                 ConvertExplicitly (true, target);
274                                 base.Error_ValueCannotBeConverted (ec, loc, target, expl);
275                         }
276                         catch
277                         {
278                                 Report.Error (31, loc, "Constant value `{0}' cannot be converted to a `{1}'",
279                                         GetValue ().ToString (), TypeManager.CSharpName (target));
280                         }
281                 }
282         }
283         
284         public class BoolConstant : Constant {
285                 public readonly bool Value;
286                 
287                 public BoolConstant (bool val, Location loc):
288                         base (loc)
289                 {
290                         type = TypeManager.bool_type;
291                         eclass = ExprClass.Value;
292
293                         Value = val;
294                 }
295
296                 override public string AsString ()
297                 {
298                         return Value ? "true" : "false";
299                 }
300
301                 public override object GetValue ()
302                 {
303                         return (object) Value;
304                 }
305                                 
306                 
307                 public override void Emit (EmitContext ec)
308                 {
309                         if (Value)
310                                 ec.ig.Emit (OpCodes.Ldc_I4_1);
311                         else
312                                 ec.ig.Emit (OpCodes.Ldc_I4_0);
313                 }
314
315                 public override Constant Increment ()
316                 {
317                         throw new NotSupportedException ();
318                 }
319         
320                 public override bool IsDefaultValue {
321                         get {
322                                 return !Value;
323                         }
324                 }
325
326                 public override bool IsNegative {
327                         get {
328                                 return false;
329                         }
330                 }
331         
332                 public override bool IsZeroInteger {
333                         get { return Value == false; }
334                 }
335
336                 public override Constant ConvertExplicitly (bool inCheckedContext, Type target_type)
337                 {
338                         return null;
339                 }
340
341         }
342
343         public class ByteConstant : IntegralConstant {
344                 public readonly byte Value;
345
346                 public ByteConstant (byte v, Location loc):
347                         base (loc)
348                 {
349                         type = TypeManager.byte_type;
350                         eclass = ExprClass.Value;
351                         Value = v;
352                 }
353
354                 public override void Emit (EmitContext ec)
355                 {
356                         IntLiteral.EmitInt (ec.ig, Value);
357                 }
358
359                 public override string AsString ()
360                 {
361                         return Value.ToString ();
362                 }
363
364                 public override object GetValue ()
365                 {
366                         return Value;
367                 }
368
369                 public override Constant Increment ()
370                 {
371                         return new ByteConstant (checked ((byte)(Value + 1)), loc);
372                 }
373
374                 public override bool IsDefaultValue {
375                         get {
376                                 return Value == 0;
377                         }
378                 }
379
380                 public override bool IsNegative {
381                         get {
382                                 return false;
383                         }
384                 }
385
386                 public override bool IsZeroInteger {
387                         get { return Value == 0; }
388                 }
389
390                 public override Constant ConvertExplicitly (bool inCheckedContext, Type target_type)
391                 {
392                         if (target_type == TypeManager.sbyte_type) {
393                                 CheckRange (inCheckedContext, Value, SByte.MinValue, SByte.MaxValue);
394                                 return new SByteConstant ((sbyte) Value, Location);
395                         }
396                         if (target_type == TypeManager.short_type)
397                                 return new ShortConstant ((short) Value, Location);
398                         if (target_type == TypeManager.ushort_type)
399                                 return new UShortConstant ((ushort) Value, Location);
400                         if (target_type == TypeManager.int32_type)
401                                 return new IntConstant ((int) Value, Location);
402                         if (target_type == TypeManager.uint32_type)
403                                 return new UIntConstant ((uint) Value, Location);
404                         if (target_type == TypeManager.int64_type)
405                                 return new LongConstant ((long) Value, Location);
406                         if (target_type == TypeManager.uint64_type)
407                                 return new ULongConstant ((ulong) Value, Location);
408                         if (target_type == TypeManager.float_type)
409                                 return new FloatConstant ((float) Value, Location);
410                         if (target_type == TypeManager.double_type)
411                                 return new DoubleConstant ((double) Value, Location);
412                         if (target_type == TypeManager.char_type)
413                                 return new CharConstant ((char) Value, Location);
414                         if (target_type == TypeManager.decimal_type)
415                                 return new DecimalConstant ((decimal) Value, Location);
416
417                         return null;
418                 }
419
420         }
421
422         public class CharConstant : Constant {
423                 public readonly char Value;
424
425                 public CharConstant (char v, Location loc):
426                         base (loc)
427                 {
428                         type = TypeManager.char_type;
429                         eclass = ExprClass.Value;
430                         Value = v;
431                 }
432
433                 public override void Emit (EmitContext ec)
434                 {
435                         IntLiteral.EmitInt (ec.ig, Value);
436                 }
437
438                 static public string descape (char c)
439                 {
440                         switch (c){
441                         case '\a':
442                                 return "\\a"; 
443                         case '\b':
444                                 return "\\b"; 
445                         case '\n':
446                                 return "\\n"; 
447                         case '\t':
448                                 return "\\t"; 
449                         case '\v':
450                                 return "\\v"; 
451                         case '\r':
452                                 return "\\r"; 
453                         case '\\':
454                                 return "\\\\";
455                         case '\f':
456                                 return "\\f"; 
457                         case '\0':
458                                 return "\\0"; 
459                         case '"':
460                                 return "\\\""; 
461                         case '\'':
462                                 return "\\\'"; 
463                         }
464                         return c.ToString ();
465                 }
466
467                 public override string AsString ()
468                 {
469                         return "\"" + descape (Value) + "\"";
470                 }
471
472                 public override object GetValue ()
473                 {
474                         return Value;
475                 }
476
477                 public override Constant Increment ()
478                 {
479                         return new CharConstant (checked ((char)(Value + 1)), loc);
480                 }
481                 
482                 public override bool IsDefaultValue {
483                         get {
484                                 return Value == 0;
485                         }
486                 }
487
488                 public override bool IsNegative {
489                         get {
490                                 return false;
491                         }
492                 }
493
494                 public override bool IsZeroInteger {
495                         get { return Value == '\0'; }
496                 }
497
498                 public override Constant ConvertExplicitly (bool inCheckedContext, Type target_type)
499                 {
500                         if (target_type == TypeManager.byte_type) {
501                                 CheckRange (inCheckedContext, Value, Byte.MinValue, Byte.MaxValue);
502                                 return new ByteConstant ((byte) Value, Location);
503                         }
504                         if (target_type == TypeManager.sbyte_type) {
505                                 CheckRange (inCheckedContext, Value, SByte.MinValue, SByte.MaxValue);
506                                 return new SByteConstant ((sbyte) Value, Location);
507                         }
508                         if (target_type == TypeManager.short_type) {
509                                 CheckRange (inCheckedContext, Value, Int16.MinValue, Int16.MaxValue);
510                                 return new ShortConstant ((short) Value, Location);
511                         }
512                         if (target_type == TypeManager.int32_type)
513                                 return new IntConstant ((int) Value, Location);
514                         if (target_type == TypeManager.uint32_type)
515                                 return new UIntConstant ((uint) Value, Location);
516                         if (target_type == TypeManager.int64_type)
517                                 return new LongConstant ((long) Value, Location);
518                         if (target_type == TypeManager.uint64_type)
519                                 return new ULongConstant ((ulong) Value, Location);
520                         if (target_type == TypeManager.float_type)
521                                 return new FloatConstant ((float) Value, Location);
522                         if (target_type == TypeManager.double_type)
523                                 return new DoubleConstant ((double) Value, Location);
524                         if (target_type == TypeManager.decimal_type)
525                                 return new DecimalConstant ((decimal) Value, Location);
526
527                         return null;
528                 }
529
530         }
531
532         public class SByteConstant : IntegralConstant {
533                 public readonly sbyte Value;
534
535                 public SByteConstant (sbyte v, Location loc):
536                         base (loc)
537                 {
538                         type = TypeManager.sbyte_type;
539                         eclass = ExprClass.Value;
540                         Value = v;
541                 }
542
543                 public override void Emit (EmitContext ec)
544                 {
545                         IntLiteral.EmitInt (ec.ig, Value);
546                 }
547
548                 public override string AsString ()
549                 {
550                         return Value.ToString ();
551                 }
552
553                 public override object GetValue ()
554                 {
555                         return Value;
556                 }
557
558                 public override Constant Increment ()
559                 {
560                     return new SByteConstant (checked((sbyte)(Value + 1)), loc);
561                 }
562
563                 public override bool IsDefaultValue {
564                         get {
565                                 return Value == 0;
566                         }
567                 }
568
569                 public override bool IsNegative {
570                         get {
571                                 return Value < 0;
572                         }
573                 }
574                 
575                 public override bool IsZeroInteger {
576                         get { return Value == 0; }
577                 }
578
579                 public override Constant ConvertExplicitly (bool inCheckedContext, Type target_type)
580                 {
581                         if (target_type == TypeManager.byte_type) {
582                                 CheckUnsigned (inCheckedContext, Value);
583                                 return new ByteConstant ((byte) Value, Location);
584                         }
585                         if (target_type == TypeManager.short_type)
586                                 return new ShortConstant ((short) Value, Location);
587                         if (target_type == TypeManager.ushort_type) {
588                                 CheckUnsigned (inCheckedContext, Value);
589                                 return new UShortConstant ((ushort) Value, Location);
590                         } if (target_type == TypeManager.int32_type)
591                                   return new IntConstant ((int) Value, Location);
592                         if (target_type == TypeManager.uint32_type) {
593                                 CheckUnsigned (inCheckedContext, Value);
594                                 return new UIntConstant ((uint) Value, Location);
595                         } if (target_type == TypeManager.int64_type)
596                                   return new LongConstant ((long) Value, Location);
597                         if (target_type == TypeManager.uint64_type) {
598                                 CheckUnsigned (inCheckedContext, Value);
599                                 return new ULongConstant ((ulong) Value, Location);
600                         }
601                         if (target_type == TypeManager.float_type)
602                                 return new FloatConstant ((float) Value, Location);
603                         if (target_type == TypeManager.double_type)
604                                 return new DoubleConstant ((double) Value, Location);
605                         if (target_type == TypeManager.char_type) {
606                                 CheckUnsigned (inCheckedContext, Value);
607                                 return new CharConstant ((char) Value, Location);
608                         }
609                         if (target_type == TypeManager.decimal_type)
610                                 return new DecimalConstant ((decimal) Value, Location);
611
612                         return null;
613                 }
614
615         }
616
617         public class ShortConstant : IntegralConstant {
618                 public readonly short Value;
619
620                 public ShortConstant (short v, Location loc):
621                         base (loc)
622                 {
623                         type = TypeManager.short_type;
624                         eclass = ExprClass.Value;
625                         Value = v;
626                 }
627
628                 public override void Emit (EmitContext ec)
629                 {
630                         IntLiteral.EmitInt (ec.ig, Value);
631                 }
632
633                 public override string AsString ()
634                 {
635                         return Value.ToString ();
636                 }
637
638                 public override object GetValue ()
639                 {
640                         return Value;
641                 }
642
643                 public override Constant Increment ()
644                 {
645                         return new ShortConstant (checked((short)(Value + 1)), loc);
646                 }
647
648                 public override bool IsDefaultValue {
649                         get {
650                                 return Value == 0;
651                         }
652                 }
653                 
654                 public override bool IsZeroInteger {
655                         get { return Value == 0; }
656                 }
657
658                 public override bool IsNegative {
659                         get {
660                                 return Value < 0;
661                         }
662                 }
663
664                 public override Constant ConvertExplicitly (bool inCheckedContext, Type target_type)
665                 {
666                         if (target_type == TypeManager.byte_type) {
667                                 CheckRange (inCheckedContext, Value, Byte.MinValue, Byte.MaxValue);
668                                 return new ByteConstant ((byte) Value, Location);
669                         }
670                         if (target_type == TypeManager.sbyte_type) {
671                                 CheckRange (inCheckedContext, Value, SByte.MinValue, SByte.MaxValue);
672                                 return new SByteConstant ((sbyte) Value, Location);
673                         }
674                         if (target_type == TypeManager.ushort_type) {
675                                 CheckUnsigned (inCheckedContext, Value);
676                                 return new UShortConstant ((ushort) Value, Location);
677                         }
678                         if (target_type == TypeManager.int32_type)
679                                 return new IntConstant ((int) Value, Location);
680                         if (target_type == TypeManager.uint32_type) {
681                                 CheckUnsigned (inCheckedContext, Value);
682                                 return new UIntConstant ((uint) Value, Location);
683                         }
684                         if (target_type == TypeManager.int64_type)
685                                 return new LongConstant ((long) Value, Location);
686                         if (target_type == TypeManager.uint64_type) {
687                                 CheckUnsigned (inCheckedContext, Value);
688                                 return new ULongConstant ((ulong) Value, Location);
689                         }
690                         if (target_type == TypeManager.float_type)
691                                 return new FloatConstant ((float) Value, Location);
692                         if (target_type == TypeManager.double_type)
693                                 return new DoubleConstant ((double) Value, Location);
694                         if (target_type == TypeManager.char_type) {
695                                 CheckRange (inCheckedContext, Value, Char.MinValue, Char.MaxValue);
696                                 return new CharConstant ((char) Value, Location);
697                         }
698                         if (target_type == TypeManager.decimal_type)
699                                 return new DecimalConstant ((decimal) Value, Location);
700
701                         return null;
702                 }
703
704         }
705
706         public class UShortConstant : IntegralConstant {
707                 public readonly ushort Value;
708
709                 public UShortConstant (ushort v, Location loc):
710                         base (loc)
711                 {
712                         type = TypeManager.ushort_type;
713                         eclass = ExprClass.Value;
714                         Value = v;
715                 }
716
717                 public override void Emit (EmitContext ec)
718                 {
719                         IntLiteral.EmitInt (ec.ig, Value);
720                 }
721
722                 public override string AsString ()
723                 {
724                         return Value.ToString ();
725                 }
726
727                 public override object GetValue ()
728                 {
729                         return Value;
730                 }
731         
732                 public override Constant Increment ()
733                 {
734                         return new UShortConstant (checked((ushort)(Value + 1)), loc);
735                 }
736
737                 public override bool IsDefaultValue {
738                         get {
739                                 return Value == 0;
740                         }
741                 }
742
743                 public override bool IsNegative {
744                         get {
745                                 return false;
746                         }
747                 }
748         
749                 public override bool IsZeroInteger {
750                         get { return Value == 0; }
751                 }
752
753                 public override Constant ConvertExplicitly (bool inCheckedContext, Type target_type)
754                 {
755                         if (target_type == TypeManager.byte_type) {
756                                 CheckRange (inCheckedContext, Value, Byte.MinValue, Byte.MaxValue);
757                                 return new ByteConstant ((byte) Value, Location);
758                         }
759                         if (target_type == TypeManager.sbyte_type) {
760                                 CheckRange (inCheckedContext, Value, SByte.MinValue, SByte.MaxValue);
761                                 return new SByteConstant ((sbyte) Value, Location);
762                         }
763                         if (target_type == TypeManager.short_type) {
764                                 CheckRange (inCheckedContext, Value, Int16.MinValue, Int16.MaxValue);
765                                 return new ShortConstant ((short) Value, Location);
766                         }
767                         if (target_type == TypeManager.int32_type)
768                                 return new IntConstant ((int) Value, Location);
769                         if (target_type == TypeManager.uint32_type)
770                                 return new UIntConstant ((uint) Value, Location);
771                         if (target_type == TypeManager.int64_type)
772                                 return new LongConstant ((long) Value, Location);
773                         if (target_type == TypeManager.uint64_type)
774                                 return new ULongConstant ((ulong) Value, Location);
775                         if (target_type == TypeManager.float_type)
776                                 return new FloatConstant ((float) Value, Location);
777                         if (target_type == TypeManager.double_type)
778                                 return new DoubleConstant ((double) Value, Location);
779                         if (target_type == TypeManager.char_type) {
780                                 CheckRange (inCheckedContext, Value, Char.MinValue, Char.MaxValue);
781                                 return new CharConstant ((char) Value, Location);
782                         }
783                         if (target_type == TypeManager.decimal_type)
784                                 return new DecimalConstant ((decimal) Value, Location);
785
786                         return null;
787                 }
788         }
789
790         public class IntConstant : IntegralConstant {
791                 public readonly int Value;
792
793                 public IntConstant (int v, Location loc):
794                         base (loc)
795                 {
796                         type = TypeManager.int32_type;
797                         eclass = ExprClass.Value;
798                         Value = v;
799                 }
800
801                 static public void EmitInt (ILGenerator ig, int i)
802                 {
803                         switch (i){
804                         case -1:
805                                 ig.Emit (OpCodes.Ldc_I4_M1);
806                                 break;
807                                 
808                         case 0:
809                                 ig.Emit (OpCodes.Ldc_I4_0);
810                                 break;
811                                 
812                         case 1:
813                                 ig.Emit (OpCodes.Ldc_I4_1);
814                                 break;
815                                 
816                         case 2:
817                                 ig.Emit (OpCodes.Ldc_I4_2);
818                                 break;
819                                 
820                         case 3:
821                                 ig.Emit (OpCodes.Ldc_I4_3);
822                                 break;
823                                 
824                         case 4:
825                                 ig.Emit (OpCodes.Ldc_I4_4);
826                                 break;
827                                 
828                         case 5:
829                                 ig.Emit (OpCodes.Ldc_I4_5);
830                                 break;
831                                 
832                         case 6:
833                                 ig.Emit (OpCodes.Ldc_I4_6);
834                                 break;
835                                 
836                         case 7:
837                                 ig.Emit (OpCodes.Ldc_I4_7);
838                                 break;
839                                 
840                         case 8:
841                                 ig.Emit (OpCodes.Ldc_I4_8);
842                                 break;
843
844                         default:
845                                 if (i >= -128 && i <= 127){
846                                         ig.Emit (OpCodes.Ldc_I4_S, (sbyte) i);
847                                 } else
848                                         ig.Emit (OpCodes.Ldc_I4, i);
849                                 break;
850                         }
851                 }
852
853                 public override void Emit (EmitContext ec)
854                 {
855                         EmitInt (ec.ig, Value);
856                 }
857
858                 public override string AsString ()
859                 {
860                         return Value.ToString ();
861                 }
862
863                 public override object GetValue ()
864                 {
865                         return Value;
866                 }
867
868                 public override Constant Increment ()
869                 {
870                         return new IntConstant (checked(Value + 1), loc);
871                 }
872
873                 public override bool IsDefaultValue {
874                         get {
875                                 return Value == 0;
876                         }
877                 }
878                 
879                 public override bool IsNegative {
880                         get {
881                                 return Value < 0;
882                         }
883                 }
884
885                 public override bool IsZeroInteger {
886                         get { return Value == 0; }
887                 }
888
889                 public override Constant ConvertExplicitly (bool inCheckedContext, Type target_type)
890                 {
891                         if (target_type == TypeManager.byte_type) {
892                                 CheckRange (inCheckedContext, Value, Byte.MinValue, Byte.MaxValue);
893                                 return new ByteConstant ((byte) Value, Location);
894                         }
895                         if (target_type == TypeManager.sbyte_type) {
896                                 CheckRange (inCheckedContext, Value, SByte.MinValue, SByte.MaxValue);
897                                 return new SByteConstant ((sbyte) Value, Location);
898                         }
899                         if (target_type == TypeManager.short_type) {
900                                 CheckRange (inCheckedContext, Value, Int16.MinValue, Int16.MaxValue);
901                                 return new ShortConstant ((short) Value, Location);
902                         }
903                         if (target_type == TypeManager.ushort_type) {
904                                 CheckRange (inCheckedContext, Value, UInt16.MinValue, UInt16.MaxValue);
905                                 return new UShortConstant ((ushort) Value, Location);
906                         }
907                         if (target_type == TypeManager.uint32_type) {
908                                 CheckRange (inCheckedContext, Value, UInt32.MinValue, UInt32.MaxValue);
909                                 return new UIntConstant ((uint) Value, Location);
910                         }
911                         if (target_type == TypeManager.int64_type)
912                                 return new LongConstant ((long) Value, Location);
913                         if (target_type == TypeManager.uint64_type) {
914                                 CheckUnsigned (inCheckedContext, Value);
915                                 return new ULongConstant ((ulong) Value, Location);
916                         }
917                         if (target_type == TypeManager.float_type)
918                                 return new FloatConstant ((float) Value, Location);
919                         if (target_type == TypeManager.double_type)
920                                 return new DoubleConstant ((double) Value, Location);
921                         if (target_type == TypeManager.char_type) {
922                                 CheckRange (inCheckedContext, Value, Char.MinValue, Char.MaxValue);
923                                 return new CharConstant ((char) Value, Location);
924                         }
925                         if (target_type == TypeManager.decimal_type)
926                                 return new DecimalConstant ((decimal) Value, Location);
927
928                         return null;
929                 }
930
931                 public override Constant ConvertImplicitly (Type type)
932                 {
933                         if (this.type == type)
934                                 return this;
935
936                         Constant c = TryImplicitIntConversion (type);
937                         if (c != null)
938                                 return c;
939
940                         return base.ConvertImplicitly (type);
941                 }
942
943                 /// <summary>
944                 ///   Attempts to perform an implicit constant conversion of the IntConstant
945                 ///   into a different data type using casts (See Implicit Constant
946                 ///   Expression Conversions)
947                 /// </summary>
948                 Constant TryImplicitIntConversion (Type target_type)
949                 {
950                         if (target_type == TypeManager.sbyte_type) {
951                                 if (Value >= SByte.MinValue && Value <= SByte.MaxValue)
952                                         return new SByteConstant ((sbyte) Value, loc);
953                         } 
954                         else if (target_type == TypeManager.byte_type) {
955                                 if (Value >= Byte.MinValue && Value <= Byte.MaxValue)
956                                         return new ByteConstant ((byte) Value, loc);
957                         } 
958                         else if (target_type == TypeManager.short_type) {
959                                 if (Value >= Int16.MinValue && Value <= Int16.MaxValue)
960                                         return new ShortConstant ((short) Value, loc);
961                         } 
962                         else if (target_type == TypeManager.ushort_type) {
963                                 if (Value >= UInt16.MinValue && Value <= UInt16.MaxValue)
964                                         return new UShortConstant ((ushort) Value, loc);
965                         } 
966                         else if (target_type == TypeManager.uint32_type) {
967                                 if (Value >= 0)
968                                         return new UIntConstant ((uint) Value, loc);
969                         } 
970                         else if (target_type == TypeManager.uint64_type) {
971                                 //
972                                 // we can optimize this case: a positive int32
973                                 // always fits on a uint64.  But we need an opcode
974                                 // to do it.
975                                 //
976                                 if (Value >= 0)
977                                         return new ULongConstant ((ulong) Value, loc);
978                         } 
979                         else if (target_type == TypeManager.double_type)
980                                 return new DoubleConstant ((double) Value, loc);
981                         else if (target_type == TypeManager.float_type)
982                                 return new FloatConstant ((float) Value, loc);
983
984                         return null;
985                 }
986         }
987
988         public class UIntConstant : IntegralConstant {
989                 public readonly uint Value;
990
991                 public UIntConstant (uint v, Location loc):
992                         base (loc)
993                 {
994                         type = TypeManager.uint32_type;
995                         eclass = ExprClass.Value;
996                         Value = v;
997                 }
998
999                 public override void Emit (EmitContext ec)
1000                 {
1001                         IntLiteral.EmitInt (ec.ig, unchecked ((int) Value));
1002                 }
1003
1004                 public override string AsString ()
1005                 {
1006                         return Value.ToString ();
1007                 }
1008
1009                 public override object GetValue ()
1010                 {
1011                         return Value;
1012                 }
1013
1014                 public override Constant Increment ()
1015                 {
1016                         return new UIntConstant (checked(Value + 1), loc);
1017                 }
1018         
1019                 public override bool IsDefaultValue {
1020                         get {
1021                                 return Value == 0;
1022                         }
1023                 }
1024
1025                 public override bool IsNegative {
1026                         get {
1027                                 return false;
1028                         }
1029                 }
1030
1031                 public override bool IsZeroInteger {
1032                         get { return Value == 0; }
1033                 }
1034
1035                 public override Constant ConvertExplicitly (bool inCheckedContext, Type target_type)
1036                 {
1037                         if (target_type == TypeManager.byte_type) {
1038                                 CheckRange (inCheckedContext, Value, Char.MinValue, Char.MaxValue);
1039                                 return new ByteConstant ((byte) Value, Location);
1040                         }
1041                         if (target_type == TypeManager.sbyte_type) {
1042                                 CheckRange (inCheckedContext, Value, SByte.MinValue, SByte.MaxValue);
1043                                 return new SByteConstant ((sbyte) Value, Location);
1044                         }
1045                         if (target_type == TypeManager.short_type) {
1046                                 CheckRange (inCheckedContext, Value, Int16.MinValue, Int16.MaxValue);
1047                                 return new ShortConstant ((short) Value, Location);
1048                         }
1049                         if (target_type == TypeManager.ushort_type) {
1050                                 CheckRange (inCheckedContext, Value, UInt16.MinValue, UInt16.MaxValue);
1051                                 return new UShortConstant ((ushort) Value, Location);
1052                         }
1053                         if (target_type == TypeManager.int32_type) {
1054                                 CheckRange (inCheckedContext, Value, Int32.MinValue, Int32.MaxValue);
1055                                 return new IntConstant ((int) Value, Location);
1056                         }
1057                         if (target_type == TypeManager.int64_type)
1058                                 return new LongConstant ((long) Value, Location);
1059                         if (target_type == TypeManager.uint64_type)
1060                                 return new ULongConstant ((ulong) Value, Location);
1061                         if (target_type == TypeManager.float_type)
1062                                 return new FloatConstant ((float) Value, Location);
1063                         if (target_type == TypeManager.double_type)
1064                                 return new DoubleConstant ((double) Value, Location);
1065                         if (target_type == TypeManager.char_type) {
1066                                 CheckRange (inCheckedContext, Value, Char.MinValue, Char.MaxValue);
1067                                 return new CharConstant ((char) Value, Location);
1068                         }
1069                         if (target_type == TypeManager.decimal_type)
1070                                 return new DecimalConstant ((decimal) Value, Location);
1071
1072                         return null;
1073                 }
1074
1075         }
1076
1077         public class LongConstant : IntegralConstant {
1078                 public readonly long Value;
1079
1080                 public LongConstant (long v, Location loc):
1081                         base (loc)
1082                 {
1083                         type = TypeManager.int64_type;
1084                         eclass = ExprClass.Value;
1085                         Value = v;
1086                 }
1087
1088                 public override void Emit (EmitContext ec)
1089                 {
1090                         EmitLong (ec.ig, Value);
1091                 }
1092
1093                 static public void EmitLong (ILGenerator ig, long l)
1094                 {
1095                         if (l >= int.MinValue && l <= int.MaxValue) {
1096                                 IntLiteral.EmitInt (ig, unchecked ((int) l));
1097                                 ig.Emit (OpCodes.Conv_I8);
1098                                 return;
1099                         }
1100                         ig.Emit (OpCodes.Ldc_I8, l);
1101                 }
1102
1103                 public override string AsString ()
1104                 {
1105                         return Value.ToString ();
1106                 }
1107
1108                 public override object GetValue ()
1109                 {
1110                         return Value;
1111                 }
1112
1113                 public override Constant Increment ()
1114                 {
1115                         return new LongConstant (checked(Value + 1), loc);
1116                 }
1117                 
1118                 public override bool IsDefaultValue {
1119                         get {
1120                                 return Value == 0;
1121                         }
1122                 }
1123
1124                 public override bool IsNegative {
1125                         get {
1126                                 return Value < 0;
1127                         }
1128                 }
1129
1130                 public override bool IsZeroInteger {
1131                         get { return Value == 0; }
1132                 }
1133
1134                 public override Constant ConvertExplicitly (bool inCheckedContext, Type target_type)
1135                 {
1136                         if (target_type == TypeManager.byte_type) {
1137                                 CheckRange (inCheckedContext, Value, Byte.MinValue, Byte.MaxValue);
1138                                 return new ByteConstant ((byte) Value, Location);
1139                         }
1140                         if (target_type == TypeManager.sbyte_type) {
1141                                 CheckRange (inCheckedContext, Value, SByte.MinValue, SByte.MaxValue);
1142                                 return new SByteConstant ((sbyte) Value, Location);
1143                         }
1144                         if (target_type == TypeManager.short_type) {
1145                                 CheckRange (inCheckedContext, Value, Int16.MinValue, Int16.MaxValue);
1146                                 return new ShortConstant ((short) Value, Location);
1147                         }
1148                         if (target_type == TypeManager.ushort_type) {
1149                                 CheckRange (inCheckedContext, Value, UInt16.MinValue, UInt16.MaxValue);
1150                                 return new UShortConstant ((ushort) Value, Location);
1151                         }
1152                         if (target_type == TypeManager.int32_type) {
1153                                 CheckRange (inCheckedContext, Value, Int32.MinValue, Int32.MaxValue);
1154                                 return new IntConstant ((int) Value, Location);
1155                         }
1156                         if (target_type == TypeManager.uint32_type) {
1157                                 CheckRange (inCheckedContext, Value, UInt32.MinValue, UInt32.MaxValue);
1158                                 return new UIntConstant ((uint) Value, Location);
1159                         }
1160                         if (target_type == TypeManager.uint64_type) {
1161                                 CheckUnsigned (inCheckedContext, Value);
1162                                 return new ULongConstant ((ulong) Value, Location);
1163                         }
1164                         if (target_type == TypeManager.float_type)
1165                                 return new FloatConstant ((float) Value, Location);
1166                         if (target_type == TypeManager.double_type)
1167                                 return new DoubleConstant ((double) Value, Location);
1168                         if (target_type == TypeManager.char_type) {
1169                                 CheckRange (inCheckedContext, Value, Char.MinValue, Char.MaxValue);
1170                                 return new CharConstant ((char) Value, Location);
1171                         }
1172                         if (target_type == TypeManager.decimal_type)
1173                                 return new DecimalConstant ((decimal) Value, Location);
1174
1175                         return null;
1176                 }
1177
1178                 public override Constant ConvertImplicitly (Type type)
1179                 {
1180                         if (Value >= 0 && type == TypeManager.uint64_type) {
1181                                 return new ULongConstant ((ulong) Value, loc);
1182                         }
1183
1184                         return base.ConvertImplicitly (type);
1185                 }
1186         }
1187
1188         public class ULongConstant : IntegralConstant {
1189                 public readonly ulong Value;
1190
1191                 public ULongConstant (ulong v, Location loc):
1192                         base (loc)
1193                 {
1194                         type = TypeManager.uint64_type;
1195                         eclass = ExprClass.Value;
1196                         Value = v;
1197                 }
1198
1199                 public override void Emit (EmitContext ec)
1200                 {
1201                         ILGenerator ig = ec.ig;
1202
1203                         LongLiteral.EmitLong (ig, unchecked ((long) Value));
1204                 }
1205
1206                 public override string AsString ()
1207                 {
1208                         return Value.ToString ();
1209                 }
1210
1211                 public override object GetValue ()
1212                 {
1213                         return Value;
1214                 }
1215
1216                 public override Constant Increment ()
1217                 {
1218                         return new ULongConstant (checked(Value + 1), loc);
1219                 }
1220
1221                 public override bool IsDefaultValue {
1222                         get {
1223                                 return Value == 0;
1224                         }
1225                 }
1226
1227                 public override bool IsNegative {
1228                         get {
1229                                 return false;
1230                         }
1231                 }
1232
1233                 public override bool IsZeroInteger {
1234                         get { return Value == 0; }
1235                 }
1236
1237                 public override Constant ConvertExplicitly (bool inCheckedContext, Type target_type)
1238                 {
1239                         if (target_type == TypeManager.byte_type) {
1240                                 CheckRange (inCheckedContext, Value, Byte.MaxValue);
1241                                 return new ByteConstant ((byte) Value, Location);
1242                         }
1243                         if (target_type == TypeManager.sbyte_type) {
1244                                 CheckRange (inCheckedContext, Value, (ulong) SByte.MaxValue);
1245                                 return new SByteConstant ((sbyte) Value, Location);
1246                         }
1247                         if (target_type == TypeManager.short_type) {
1248                                 CheckRange (inCheckedContext, Value, (ulong) Int16.MaxValue);
1249                                 return new ShortConstant ((short) Value, Location);
1250                         }
1251                         if (target_type == TypeManager.ushort_type) {
1252                                 CheckRange (inCheckedContext, Value, UInt16.MaxValue);
1253                                 return new UShortConstant ((ushort) Value, Location);
1254                         }
1255                         if (target_type == TypeManager.int32_type) {
1256                                 CheckRange (inCheckedContext, Value, Int32.MaxValue);
1257                                 return new IntConstant ((int) Value, Location);
1258                         }
1259                         if (target_type == TypeManager.uint32_type) {
1260                                 CheckRange (inCheckedContext, Value, UInt32.MaxValue);
1261                                 return new UIntConstant ((uint) Value, Location);
1262                         }
1263                         if (target_type == TypeManager.int64_type) {
1264                                 CheckRange (inCheckedContext, Value, (ulong) Int64.MaxValue);
1265                                 return new LongConstant ((long) Value, Location);
1266                         }
1267                         if (target_type == TypeManager.float_type)
1268                                 return new FloatConstant ((float) Value, Location);
1269                         if (target_type == TypeManager.double_type)
1270                                 return new DoubleConstant ((double) Value, Location);
1271                         if (target_type == TypeManager.char_type) {
1272                                 CheckRange (inCheckedContext, Value, Char.MaxValue);
1273                                 return new CharConstant ((char) Value, Location);
1274                         }
1275                         if (target_type == TypeManager.decimal_type)
1276                                 return new DecimalConstant ((decimal) Value, Location);
1277
1278                         return null;
1279                 }
1280
1281         }
1282
1283         public class FloatConstant : Constant {
1284                 public float Value;
1285
1286                 public FloatConstant (float v, Location loc):
1287                         base (loc)
1288                 {
1289                         type = TypeManager.float_type;
1290                         eclass = ExprClass.Value;
1291                         Value = v;
1292                 }
1293
1294                 public override void Emit (EmitContext ec)
1295                 {
1296                         ec.ig.Emit (OpCodes.Ldc_R4, Value);
1297                 }
1298
1299                 public override string AsString ()
1300                 {
1301                         return Value.ToString ();
1302                 }
1303
1304                 public override object GetValue ()
1305                 {
1306                         return Value;
1307                 }
1308
1309                 public override Constant Increment ()
1310                 {
1311                         return new FloatConstant (checked(Value + 1), loc);
1312                 }
1313
1314                 public override bool IsDefaultValue {
1315                         get {
1316                                 return Value == 0;
1317                         }
1318                 }
1319
1320                 public override bool IsNegative {
1321                         get {
1322                                 return Value < 0;
1323                         }
1324                 }
1325
1326                 public override Constant ConvertExplicitly (bool inCheckedContext, Type target_type)
1327                 {
1328                         if (target_type == TypeManager.byte_type) {
1329                                 CheckRange (inCheckedContext, Value, byte.MinValue, byte.MaxValue);
1330                                 return new ByteConstant ((byte) Value, Location);
1331                         }
1332                         if (target_type == TypeManager.sbyte_type) {
1333                                 CheckRange (inCheckedContext, Value,  sbyte.MinValue, sbyte.MaxValue);
1334                                 return new SByteConstant ((sbyte) Value, Location);
1335                         }
1336                         if (target_type == TypeManager.short_type) {
1337                                 CheckRange (inCheckedContext, Value, short.MinValue, short.MaxValue);
1338                                 return new ShortConstant ((short) Value, Location);
1339                         }
1340                         if (target_type == TypeManager.ushort_type) {
1341                                 CheckRange (inCheckedContext, Value, ushort.MinValue, ushort.MaxValue);
1342                                 return new UShortConstant ((ushort) Value, Location);
1343                         }
1344                         if (target_type == TypeManager.int32_type) {
1345                                 CheckRange (inCheckedContext, Value, int.MinValue, int.MaxValue);
1346                                 return new IntConstant ((int) Value, Location);
1347                         }
1348                         if (target_type == TypeManager.uint32_type) {
1349                                 CheckRange (inCheckedContext, Value, uint.MinValue, uint.MaxValue);
1350                                 return new UIntConstant ((uint) Value, Location);
1351                         }
1352                         if (target_type == TypeManager.int64_type) {
1353                                 CheckRange (inCheckedContext, Value, long.MinValue, long.MaxValue);
1354                                 return new LongConstant ((long) Value, Location);
1355                         }
1356                         if (target_type == TypeManager.uint64_type) {
1357                                 CheckRange (inCheckedContext, Value, ulong.MinValue, ulong.MaxValue);
1358                                 return new ULongConstant ((ulong) Value, Location);
1359                         }
1360                         if (target_type == TypeManager.double_type)
1361                                 return new DoubleConstant ((double) Value, Location);
1362                         if (target_type == TypeManager.char_type) {
1363                                 CheckRange (inCheckedContext, Value, char.MinValue, char.MaxValue);
1364                                 return new CharConstant ((char) Value, Location);
1365                         }
1366                         if (target_type == TypeManager.decimal_type)
1367                                 return new DecimalConstant ((decimal) Value, Location);
1368
1369                         return null;
1370                 }
1371
1372         }
1373
1374         public class DoubleConstant : Constant {
1375                 public double Value;
1376
1377                 public DoubleConstant (double v, Location loc):
1378                         base (loc)
1379                 {
1380                         type = TypeManager.double_type;
1381                         eclass = ExprClass.Value;
1382                         Value = v;
1383                 }
1384
1385                 public override void Emit (EmitContext ec)
1386                 {
1387                         ec.ig.Emit (OpCodes.Ldc_R8, Value);
1388                 }
1389
1390                 public override string AsString ()
1391                 {
1392                         return Value.ToString ();
1393                 }
1394
1395                 public override object GetValue ()
1396                 {
1397                         return Value;
1398                 }
1399
1400                 public override Constant Increment ()
1401                 {
1402                         return new DoubleConstant (checked(Value + 1), loc);
1403                 }
1404
1405                 public override bool IsDefaultValue {
1406                         get {
1407                                 return Value == 0;
1408                         }
1409                 }
1410
1411                 public override bool IsNegative {
1412                         get {
1413                                 return Value < 0;
1414                         }
1415                 }
1416
1417                 public override Constant ConvertExplicitly (bool inCheckedContext, Type target_type)
1418                 {
1419                         if (target_type == TypeManager.byte_type) {
1420                                 CheckRange (inCheckedContext, Value, Byte.MinValue, Byte.MaxValue);
1421                                 return new ByteConstant ((byte) Value, Location);
1422                         }
1423                         if (target_type == TypeManager.sbyte_type) {
1424                                 CheckRange (inCheckedContext, Value, SByte.MinValue, SByte.MaxValue);
1425                                 return new SByteConstant ((sbyte) Value, Location);
1426                         }
1427                         if (target_type == TypeManager.short_type) {
1428                                 CheckRange (inCheckedContext, Value, short.MinValue, short.MaxValue);
1429                                 return new ShortConstant ((short) Value, Location);
1430                         }
1431                         if (target_type == TypeManager.ushort_type) {
1432                                 CheckRange (inCheckedContext, Value, ushort.MinValue, ushort.MaxValue);
1433                                 return new UShortConstant ((ushort) Value, Location);
1434                         }
1435                         if (target_type == TypeManager.int32_type) {
1436                                 CheckRange (inCheckedContext, Value, int.MinValue, int.MaxValue);
1437                                 return new IntConstant ((int) Value, Location);
1438                         }
1439                         if (target_type == TypeManager.uint32_type) {
1440                                 CheckRange (inCheckedContext, Value, uint.MinValue, uint.MaxValue);
1441                                 return new UIntConstant ((uint) Value, Location);
1442                         }
1443                         if (target_type == TypeManager.int64_type) {
1444                                 CheckRange (inCheckedContext, Value, long.MinValue, long.MaxValue);
1445                                 return new LongConstant ((long) Value, Location);
1446                         }
1447                         if (target_type == TypeManager.uint64_type) {
1448                                 CheckRange (inCheckedContext, Value, ulong.MinValue, ulong.MaxValue);
1449                                 return new ULongConstant ((ulong) Value, Location);
1450                         }
1451                         if (target_type == TypeManager.float_type)
1452                                 return new FloatConstant ((float) Value, Location);
1453                         if (target_type == TypeManager.char_type) {
1454                                 CheckRange (inCheckedContext, Value, char.MinValue, char.MaxValue);
1455                                 return new CharConstant ((char) Value, Location);
1456                         }
1457                         if (target_type == TypeManager.decimal_type)
1458                                 return new DecimalConstant ((decimal) Value, Location);
1459
1460                         return null;
1461                 }
1462
1463         }
1464
1465         public class DecimalConstant : Constant {
1466                 public readonly decimal Value;
1467
1468                 public DecimalConstant (decimal d, Location loc):
1469                         base (loc)
1470                 {
1471                         type = TypeManager.decimal_type;
1472                         eclass = ExprClass.Value;
1473                         Value = d;
1474                 }
1475
1476                 override public string AsString ()
1477                 {
1478                         return Value.ToString ();
1479                 }
1480
1481                 public override object GetValue ()
1482                 {
1483                         return (object) Value;
1484                 }
1485
1486                 public override void Emit (EmitContext ec)
1487                 {
1488                         ILGenerator ig = ec.ig;
1489
1490                         int [] words = Decimal.GetBits (Value);
1491                         int power = (words [3] >> 16) & 0xff;
1492
1493                         if (power == 0 && Value <= int.MaxValue && Value >= int.MinValue)
1494                         {
1495                                 IntConstant.EmitInt (ig, (int)Value);
1496                                 ig.Emit (OpCodes.Newobj, TypeManager.void_decimal_ctor_int_arg);
1497                                 return;
1498                         }
1499
1500                         
1501                         //
1502                         // FIXME: we could optimize this, and call a better 
1503                         // constructor
1504                         //
1505
1506                         IntConstant.EmitInt (ig, words [0]);
1507                         IntConstant.EmitInt (ig, words [1]);
1508                         IntConstant.EmitInt (ig, words [2]);
1509
1510                         // sign
1511                         IntConstant.EmitInt (ig, words [3] >> 31);
1512
1513                         // power
1514                         IntConstant.EmitInt (ig, power);
1515
1516                         ig.Emit (OpCodes.Newobj, TypeManager.void_decimal_ctor_five_args);
1517                 }
1518
1519                 public override Constant Increment ()
1520                 {
1521                         return new DecimalConstant (checked (Value + 1), loc);
1522                 }
1523
1524                 public override bool IsDefaultValue {
1525                         get {
1526                                 return Value == 0;
1527                         }
1528                 }
1529
1530                 public override bool IsNegative {
1531                         get {
1532                                 return Value < 0;
1533                         }
1534                 }
1535
1536                 public override Constant ConvertExplicitly (bool inCheckedContext, Type target_type)
1537                 {
1538                         if (target_type == TypeManager.sbyte_type)
1539                                 return new SByteConstant ((sbyte)Value, loc);
1540                         if (target_type == TypeManager.byte_type)
1541                                 return new ByteConstant ((byte)Value, loc);
1542                         if (target_type == TypeManager.short_type)
1543                                 return new ShortConstant ((short)Value, loc);
1544                         if (target_type == TypeManager.ushort_type)
1545                                 return new UShortConstant ((ushort)Value, loc);
1546                         if (target_type == TypeManager.int32_type)
1547                                 return new IntConstant ((int)Value, loc);
1548                         if (target_type == TypeManager.uint32_type)
1549                                 return new UIntConstant ((uint)Value, loc);
1550                         if (target_type == TypeManager.int64_type)
1551                                 return new LongConstant ((long)Value, loc);
1552                         if (target_type == TypeManager.uint64_type)
1553                                 return new ULongConstant ((ulong)Value, loc);
1554                         if (target_type == TypeManager.char_type)
1555                                 return new CharConstant ((char)Value, loc);
1556                         if (target_type == TypeManager.float_type)
1557                                 return new FloatConstant ((float)Value, loc);
1558                         if (target_type == TypeManager.double_type)
1559                                 return new DoubleConstant ((double)Value, loc);
1560
1561                         return null;
1562                 }
1563
1564         }
1565
1566         public class StringConstant : Constant {
1567                 public readonly string Value;
1568
1569                 public StringConstant (string s, Location loc):
1570                         base (loc)
1571                 {
1572                         type = TypeManager.string_type;
1573                         eclass = ExprClass.Value;
1574                         Value = s;
1575                 }
1576
1577                 // FIXME: Escape the string.
1578                 override public string AsString ()
1579                 {
1580                         return "\"" + Value + "\"";
1581                 }
1582
1583                 public override object GetValue ()
1584                 {
1585                         return Value;
1586                 }
1587                 
1588                 public override void Emit (EmitContext ec)
1589                 {
1590                         if (Value == null)
1591                                 ec.ig.Emit (OpCodes.Ldnull);
1592                         else
1593                                 ec.ig.Emit (OpCodes.Ldstr, Value);
1594                 }
1595
1596                 public override Constant Increment ()
1597                 {
1598                         throw new NotSupportedException ();
1599                 }
1600
1601                 public override bool IsDefaultValue {
1602                         get {
1603                                 return Value == null;
1604                         }
1605                 }
1606
1607                 public override bool IsNegative {
1608                         get {
1609                                 return false;
1610                         }
1611                 }
1612
1613                 public override Constant ConvertExplicitly (bool inCheckedContext, Type target_type)
1614                 {
1615                         return null;
1616                 }
1617         }
1618
1619 }
1620
1621