2009-01-30 Miguel de Icaza <miguel@novell.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 // Copyright 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 CreateExpressionTree (EmitContext ec)
45                 {
46                         // HACK: change type to be object
47                         type = TypeManager.object_type;
48                         return base.CreateExpressionTree (ec);
49                 }               
50
51                 public override Expression DoResolve (EmitContext ec)
52                 {
53                         return this;
54                 }
55
56                 public override void Emit (EmitContext ec)
57                 {
58                         ec.ig.Emit (OpCodes.Ldnull);
59                 }
60
61                 public override string ExprClassName {
62                         get {
63                                 return GetSignatureForError ();
64                         }
65                 }
66
67                 public override string GetSignatureForError ()
68                 {
69                         return "null";
70                 }
71
72                 public override void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type t, bool expl)
73                 {
74                         if (TypeManager.IsGenericParameter (t)) {
75                                 Report.Error(403, loc,
76                                         "Cannot convert null to the type parameter `{0}' because it could be a value " +
77                                         "type. Consider using `default ({0})' instead", t.Name);
78                         } else {
79                                 Report.Error(37, loc, "Cannot convert null to `{0}' because it is a value type",
80                                         TypeManager.CSharpName(t));
81                         }
82                 }
83
84                 public override Constant ConvertExplicitly (bool inCheckedContext, Type targetType)
85                 {
86                         if (targetType.IsPointer)
87                                 return new EmptyConstantCast (new NullPointer (loc), targetType);
88
89                         // Exlude internal compiler types
90                         if (targetType == TypeManager.anonymous_method_type)
91                                 return null;
92
93                         if (TypeManager.IsReferenceType (targetType))
94                                 return new EmptyConstantCast (this, targetType);
95
96                         if (TypeManager.IsNullableType (targetType))
97                                 return Nullable.LiftedNull.Create (targetType, loc);
98
99                         return null;
100                 }
101
102                 public override Constant ConvertImplicitly (Type targetType)
103                 {
104                         //
105                         // Null literal is of object type
106                         //
107                         if (targetType == TypeManager.object_type)
108                                 return this;
109
110                         return ConvertExplicitly (false, targetType);
111                 }
112
113                 public override object GetValue ()
114                 {
115                         return null;
116                 }
117
118                 public override Constant Increment ()
119                 {
120                         throw new NotSupportedException ();
121                 }
122
123                 public override bool IsDefaultValue 
124                 {
125                         get { return true; }
126                 }
127
128                 public override bool IsLiteral {
129                         get { return true; }
130                 }
131
132                 public override bool IsNegative {
133                         get { return false; }
134                 }
135
136                 public override bool IsNull {
137                         get { return true; }
138                 }
139
140                 public override bool IsZeroInteger {
141                         get { return true; }
142                 }
143         }
144
145         //
146         // A null literal in a pointer context
147         //
148         public class NullPointer : NullLiteral {
149                 public NullPointer (Location loc):
150                         base (loc)
151                 {
152                         type = TypeManager.object_type;
153                 }
154
155                 public override void Emit (EmitContext ec)
156                 {
157                         ILGenerator ig = ec.ig;
158                                 
159                         //
160                         // Emits null pointer
161                         //
162                         ig.Emit (OpCodes.Ldc_I4_0);
163                         ig.Emit (OpCodes.Conv_U);
164                 }
165         }
166
167         public class BoolLiteral : BoolConstant {
168                 public BoolLiteral (bool val, Location loc) : base (val, loc)
169                 {
170                 }
171
172                 public override Expression DoResolve (EmitContext ec)
173                 {
174                         type = TypeManager.bool_type;
175                         return this;
176                 }
177
178                 public override bool IsLiteral {
179                         get { return true; }
180                 }
181         }
182
183         public class CharLiteral : CharConstant {
184                 public CharLiteral (char c, Location loc) : base (c, loc)
185                 {
186                 }
187
188                 public override Expression DoResolve (EmitContext ec)
189                 {
190                         type = TypeManager.char_type;
191                         return this;
192                 }
193
194                 public override bool IsLiteral {
195                         get { return true; }
196                 }
197         }
198
199         public class IntLiteral : IntConstant {
200                 public IntLiteral (int l, Location loc) : base (l, loc)
201                 {
202                 }
203
204                 public override Expression DoResolve (EmitContext ec)
205                 {
206                         type = TypeManager.int32_type;
207                         return this;
208                 }
209
210                 public override Constant ConvertImplicitly (Type type)
211                 {
212                         ///
213                         /// The 0 literal can be converted to an enum value,
214                         ///
215                         if (Value == 0 && TypeManager.IsEnumType (type)) {
216                                 Constant c = ConvertImplicitly (TypeManager.GetEnumUnderlyingType (type));
217                                 if (c == null)
218                                         return null;
219
220                                 return new EnumConstant (c, type);
221                         }
222                         return base.ConvertImplicitly (type);
223                 }
224
225                 public override bool IsLiteral {
226                         get { return true; }
227                 }
228         }
229
230         public class UIntLiteral : UIntConstant {
231                 public UIntLiteral (uint l, Location loc) : base (l, loc)
232                 {
233                 }
234
235                 public override Expression DoResolve (EmitContext ec)
236                 {
237                         type = TypeManager.uint32_type;
238                         return this;
239                 }
240
241                 public override bool IsLiteral {
242                         get { return true; }
243                 }
244         }
245         
246         public class LongLiteral : LongConstant {
247                 public LongLiteral (long l, Location loc) : base (l, loc)
248                 {
249                 }
250
251                 public override Expression DoResolve (EmitContext ec)
252                 {
253                         type = TypeManager.int64_type;
254                         return this;
255                 }
256
257                 public override bool IsLiteral {
258                         get { return true; }
259                 }
260         }
261
262         public class ULongLiteral : ULongConstant {
263                 public ULongLiteral (ulong l, Location loc) : base (l, loc)
264                 {
265                 }
266
267                 public override Expression DoResolve (EmitContext ec)
268                 {
269                         type = TypeManager.uint64_type;
270                         return this;
271                 }
272
273                 public override bool IsLiteral {
274                         get { return true; }
275                 }
276         }
277         
278         public class FloatLiteral : FloatConstant {
279                 
280                 public FloatLiteral (float f, Location loc) : base (f, loc)
281                 {
282                 }
283
284                 public override Expression DoResolve (EmitContext ec)
285                 {
286                         type = TypeManager.float_type;
287                         return this;
288                 }
289
290                 public override bool IsLiteral {
291                         get { return true; }
292                 }
293
294         }
295
296         public class DoubleLiteral : DoubleConstant {
297                 public DoubleLiteral (double d, Location loc) : base (d, loc)
298                 {
299                 }
300
301                 public override Expression DoResolve (EmitContext ec)
302                 {
303                         type = TypeManager.double_type;
304
305                         return this;
306                 }
307
308                 public override void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
309                 {
310                         if (target == TypeManager.float_type) {
311                                 Error_664 (loc, "float", "f");
312                                 return;
313                         }
314
315                         if (target == TypeManager.decimal_type) {
316                                 Error_664 (loc, "decimal", "m");
317                                 return;
318                         }
319
320                         base.Error_ValueCannotBeConverted (ec, loc, target, expl);
321                 }
322
323                 static void Error_664 (Location loc, string type, string suffix)
324                 {
325                         Report.Error (664, loc,
326                                 "Literal of type double cannot be implicitly converted to type `{0}'. Add suffix `{1}' to create a literal of this type",
327                                 type, suffix);
328                 }
329
330                 public override bool IsLiteral {
331                         get { return true; }
332                 }
333
334         }
335
336         public class DecimalLiteral : DecimalConstant {
337                 public DecimalLiteral (decimal d, Location loc) : base (d, loc)
338                 {
339                 }
340
341                 public override Expression DoResolve (EmitContext ec)
342                 {
343                         type = TypeManager.decimal_type;
344                         return this;
345                 }
346
347                 public override bool IsLiteral {
348                         get { return true; }
349                 }
350         }
351
352         public class StringLiteral : StringConstant {
353                 public StringLiteral (string s, Location loc) : base (s, loc)
354                 {
355                 }
356
357                 public override Expression DoResolve (EmitContext ec)
358                 {
359                         type = TypeManager.string_type;
360
361                         return this;
362                 }
363
364                 public override bool IsLiteral {
365                         get { return true; }
366                 }
367
368         }
369 }