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