2008-03-04 Marek Safar <marek.safar@gmail.com>
[mono.git] / mcs / mcs / literal.cs
1 //
2 // literal.cs: Literal representation for the IL tree.
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 // Notice that during parsing we create objects of type Literal, but the
12 // types are not loaded (thats why the Resolve method has to assign the
13 // type at that point).
14 //
15 // Literals differ from the constants in that we know we encountered them
16 // as a literal in the source code (and some extra rules apply there) and
17 // they have to be resolved (since during parsing we have not loaded the
18 // types yet) while constants are created only after types have been loaded
19 // and are fully resolved when born.
20 //
21
22 using System;
23 using System.Reflection;
24 using System.Reflection.Emit;
25
26 namespace Mono.CSharp {
27
28         //
29         // The null literal
30         //
31         public class NullLiteral : Constant {
32                 public NullLiteral (Location loc):
33                         base (loc)
34                 {
35                         eclass = ExprClass.Value;
36                         type = typeof (NullLiteral);
37                 }
38
39                 override public string AsString ()
40                 {
41                         return GetSignatureForError ();
42                 }
43
44                 public override Expression DoResolve (EmitContext ec)
45                 {
46                         return this;
47                 }
48
49                 public override void Emit (EmitContext ec)
50                 {
51                         ec.ig.Emit (OpCodes.Ldnull);
52                 }
53
54                 public override string ExprClassName {
55                         get {
56                                 return GetSignatureForError ();
57                         }
58                 }
59
60                 public override string GetSignatureForError ()
61                 {
62                         return "null";
63                 }
64
65                 public override void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type t, bool expl)
66                 {
67                         if (TypeManager.IsGenericParameter (t)) {
68                                 Report.Error(403, loc,
69                                         "Cannot convert null to the type parameter `{0}' because it could be a value " +
70                                         "type. Consider using `default ({0})' instead", t.Name);
71                         } else {
72                                 Report.Error(37, loc, "Cannot convert null to `{0}' because it is a value type",
73                                         TypeManager.CSharpName(t));
74                         }
75                 }
76
77                 public override Constant ConvertImplicitly (Type targetType)
78                 {
79                         if (targetType.IsPointer)
80                                 return new EmptyConstantCast (NullPointer.Null, targetType);
81
82                         if (TypeManager.IsReferenceType (targetType))
83                                 return new EmptyConstantCast (this, targetType);
84
85                         return null;
86                 }
87
88                 public override object GetValue ()
89                 {
90                         return null;
91                 }
92
93                 public override Constant Increment ()
94                 {
95                         throw new NotSupportedException ();
96                 }
97
98                 public override bool IsDefaultValue 
99                 {
100                         get { return true; }
101                 }
102
103                 public override bool IsNegative 
104                 {
105                         get { return false; }
106                 }
107
108                 public override bool IsNull {
109                         get { return true; }
110                 }
111
112                 public override bool IsZeroInteger 
113                 {
114                         get { return true; }
115                 }
116
117                 public override Constant ConvertExplicitly(bool inCheckedContext, Type target_type)
118                 {
119                         if (!TypeManager.IsValueType (target_type))
120                                 return new EmptyConstantCast (this, target_type);
121
122                         return null;
123                 }
124         }
125
126         //
127         // A null literal in a pointer context
128         //
129         public class NullPointer : NullLiteral {
130                 public static readonly NullLiteral Null = new NullPointer ();
131
132                 private NullPointer ():
133                         base (Location.Null)
134                 {
135                         type = TypeManager.object_type;
136                 }
137
138                 public override void Emit (EmitContext ec)
139                 {
140                         ILGenerator ig = ec.ig;
141                                 
142                         // TODO: why not use Ldnull instead ?
143                         ig.Emit (OpCodes.Ldc_I4_0);
144                         ig.Emit (OpCodes.Conv_U);
145                 }
146         }
147
148         public class BoolLiteral : BoolConstant {
149                 public BoolLiteral (bool val, Location loc) : base (val, loc)
150                 {
151                 }
152
153                 public override Expression DoResolve (EmitContext ec)
154                 {
155                         type = TypeManager.bool_type;
156                         return this;
157                 }
158         }
159
160         public class CharLiteral : CharConstant {
161                 public CharLiteral (char c, Location loc) : base (c, loc)
162                 {
163                 }
164
165                 public override Expression DoResolve (EmitContext ec)
166                 {
167                         type = TypeManager.char_type;
168                         return this;
169                 }
170         }
171
172         public class IntLiteral : IntConstant {
173                 public IntLiteral (int l, Location loc) : base (l, loc)
174                 {
175                 }
176
177                 public override Expression DoResolve (EmitContext ec)
178                 {
179                         type = TypeManager.int32_type;
180                         return this;
181                 }
182
183                 public override Constant ConvertImplicitly (Type type)
184                 {
185                         ///
186                         /// The 0 literal can be converted to an enum value,
187                         ///
188                         if (Value == 0 && TypeManager.IsEnumType (type)) {
189                                 Constant c = ConvertImplicitly (TypeManager.EnumToUnderlying (type));
190                                 if (c == null)
191                                         return null;
192
193                                 return new EnumConstant (c, type);
194                         }
195                         return base.ConvertImplicitly (type);
196                 }
197
198         }
199
200         public class UIntLiteral : UIntConstant {
201                 public UIntLiteral (uint l, Location loc) : base (l, loc)
202                 {
203                 }
204
205                 public override Expression DoResolve (EmitContext ec)
206                 {
207                         type = TypeManager.uint32_type;
208                         return this;
209                 }
210         }
211         
212         public class LongLiteral : LongConstant {
213                 public LongLiteral (long l, Location loc) : base (l, loc)
214                 {
215                 }
216
217                 public override Expression DoResolve (EmitContext ec)
218                 {
219                         type = TypeManager.int64_type;
220
221                         return this;
222                 }
223         }
224
225         public class ULongLiteral : ULongConstant {
226                 public ULongLiteral (ulong l, Location loc) : base (l, loc)
227                 {
228                 }
229
230                 public override Expression DoResolve (EmitContext ec)
231                 {
232                         type = TypeManager.uint64_type;
233                         return this;
234                 }
235         }
236         
237         public class FloatLiteral : FloatConstant {
238                 
239                 public FloatLiteral (float f, Location loc) : base (f, loc)
240                 {
241                 }
242
243                 public override Expression DoResolve (EmitContext ec)
244                 {
245                         type = TypeManager.float_type;
246                         return this;
247                 }
248         }
249
250         public class DoubleLiteral : DoubleConstant {
251                 public DoubleLiteral (double d, Location loc) : base (d, loc)
252                 {
253                 }
254
255                 public override Expression DoResolve (EmitContext ec)
256                 {
257                         type = TypeManager.double_type;
258
259                         return this;
260                 }
261
262                 public override void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
263                 {
264                         if (target == TypeManager.float_type) {
265                                 Error_664 (loc, "float", "f");
266                                 return;
267                         }
268
269                         if (target == TypeManager.decimal_type) {
270                                 Error_664 (loc, "decimal", "m");
271                                 return;
272                         }
273
274                         base.Error_ValueCannotBeConverted (ec, loc, target, expl);
275                 }
276
277                 static void Error_664 (Location loc, string type, string suffix)
278                 {
279                         Report.Error (664, loc,
280                                 "Literal of type double cannot be implicitly converted to type `{0}'. Add suffix `{1}' to create a literal of this type",
281                                 type, suffix);
282                 }
283         }
284
285         public class DecimalLiteral : DecimalConstant {
286                 public DecimalLiteral (decimal d, Location loc) : base (d, loc)
287                 {
288                 }
289
290                 public override Expression DoResolve (EmitContext ec)
291                 {
292                         type = TypeManager.decimal_type;
293                         return this;
294                 }
295         }
296
297         public class StringLiteral : StringConstant {
298                 public StringLiteral (string s, Location loc) : base (s, loc)
299                 {
300                 }
301
302                 public override Expression DoResolve (EmitContext ec)
303                 {
304                         type = TypeManager.string_type;
305
306                         return this;
307                 }
308         }
309 }