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