2005-07-13 Maverson Eduardo Schulze Rosa <maverson@gmail.com>
[mono.git] / mcs / mbas / const.cs
1 //
2 // const.cs: Constant declarations.
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //
7 // (C) 2001 Ximian, Inc.
8 //
9 //
10
11 //
12 // This is needed because the following situation arises:
13 //
14 //     The FieldBuilder is declared with the real type for an enumeration
15 //
16 //     When we attempt to set the value for the constant, the FieldBuilder.SetConstant
17 //     function aborts because it requires its argument to be of the same type
18 //
19
20 using System;
21
22 namespace Mono.MonoBASIC {
23
24
25         using System;
26         using System.Reflection;
27         using System.Reflection.Emit;
28         using System.Collections;
29
30         public class Const : MemberCore {
31                 public Expression ConstantType;
32                 public Expression Expr;
33                 public FieldBuilder FieldBuilder;
34
35
36                 bool resolved = false;
37                 object ConstantValue = null;
38                 Type type;
39
40                 bool in_transit = false;
41
42                 public const int AllowedModifiers =
43                         Modifiers.PUBLIC |
44                         Modifiers.PROTECTED |
45                         Modifiers.INTERNAL |
46                         Modifiers.PRIVATE |
47                         Modifiers.SHADOWS;
48
49                 public Const (Expression constant_type, string name, Expression expr, int mod_flags,
50                               Attributes attrs, Location loc)
51                         : base (name, attrs, loc)
52                 {
53                         ConstantType = constant_type;
54                         Name = name;
55                         Expr = expr;
56                         ModFlags = Modifiers.Check (AllowedModifiers, mod_flags, Modifiers.PRIVATE, loc);
57                 }
58
59                 public override AttributeTargets AttributeTargets {
60                         get {
61                                 return AttributeTargets.Field;
62                         }
63                 }
64
65                 public FieldAttributes FieldAttr {
66                         get {
67                                 return FieldAttributes.Literal | FieldAttributes.Static |
68                                         Modifiers.FieldAttr (ModFlags) ;
69                         }
70                 }
71
72 #if DEBUG
73                 void dump_tree (Type t)
74                 {
75                         Console.WriteLine ("Dumping hierarchy");
76                         while (t != null){
77                                 Console.WriteLine ("   " + t.FullName + " " +
78                                         (t.GetType ().IsEnum ? "yes" : "no"));
79                                 t = t.BaseType;
80                         }
81                 }
82 #endif
83
84                 /// <summary>
85                 ///   Defines the constant in the @parent
86                 /// </summary>
87                 public override bool Define (TypeContainer parent)
88                 {
89                         type = parent.ResolveType (ConstantType, false, Location);
90
91                         if (type == null)
92                                 return false;
93
94                         if (!TypeManager.IsBuiltinType (type) &&
95                             (!type.IsSubclassOf (TypeManager.enum_type))) {
96                                 Report.Error (
97                                         30424, Location,
98                                         "Constant type is not valid (only system types are allowed)");
99                                 return false;
100                         }
101
102                         // if no type is declared expicitely 
103                         // set the expression type as the type of constant
104                         if (type == TypeManager.object_type){
105                                 if (Expr is IntLiteral)
106                                         type = TypeManager.int32_type;
107                                 else if (Expr is UIntLiteral)
108                                         type = TypeManager.uint32_type;
109                                 else if (Expr is LongLiteral)
110                                         type = TypeManager.int64_type;
111                                 else if (Expr is ULongLiteral)
112                                         type = TypeManager.uint64_type;
113                                 else if (Expr is FloatLiteral)
114                                         type = TypeManager.float_type;
115                                 else if (Expr is DoubleLiteral)
116                                         type = TypeManager.double_type;
117                                 else if (Expr is StringLiteral)
118                                         type = TypeManager.string_type;
119                                 else if (Expr is ShortLiteral)
120                                         type = TypeManager.short_type;
121                                 else if (Expr is UShortConstant)
122                                         type = TypeManager.ushort_type;
123                                 else if (Expr is SByteConstant)
124                                         type = TypeManager.sbyte_type;
125                                 else if (Expr is ByteConstant)
126                                         type = TypeManager.byte_type;
127                                 else if (Expr is CharConstant)
128                                         type = TypeManager.char_type;
129                                 else if (Expr is BoolConstant)
130                                         type = TypeManager.bool_type;
131                                 else if (Expr is DateConstant)
132                                         type = TypeManager.date_type;
133                         }
134                         Type ptype = parent.TypeBuilder.BaseType;
135
136                         if (ptype != null) {
137                                 MemberList list = TypeContainer.FindMembers (
138                                         ptype, MemberTypes.Field, BindingFlags.Public,
139                                         Type.FilterName, Name);
140                                 
141                                 if ((list.Count > 0) && ((ModFlags & Modifiers.SHADOWS) == 0))
142                                         Report.Warning (
143                                                 40004, 2, Location, 
144                                                 "Const '" + Name + "' should be declared " +
145                                                 "Shadows since the base type '" + ptype.Name + 
146                                                 "' has a Const with same name");
147                                 if (list.Count == 0) {
148                                         // if a member of module is not inherited from Object class
149                                         // can not be declared protected
150                                         if ((parent is Module) && ((ModFlags & Modifiers.PROTECTED) != 0))
151                                                 Report.Error (30593, Location,
152                                                         "'Const' inside a 'Module' can not be " +
153                                                         "declared as 'Protected'");
154
155                                         /*if ((ModFlags & Modifiers.NEW) != 0)
156                                                 WarningNotHiding (parent);*/
157                                 }
158                         } 
159                         /*else if ((ModFlags & Modifiers.NEW) != 0)
160                                 WarningNotHiding (parent);*/
161
162                         if ((parent is Struct) && ((ModFlags & Modifiers.PROTECTED) != 0))
163                                 Report.Error (30435, Location,
164                                         "'Const' inside a 'Structure' can not be " +
165                                         "declared as 'Protected'");
166
167                         FieldBuilder = parent.TypeBuilder.DefineField (Name, type, FieldAttr);
168
169                         TypeManager.RegisterConstant (FieldBuilder, this);
170
171                         return true;
172                 }
173
174                 //
175                 // Changes the type of the constant expression `expr' to the Type `type'
176                 // Returns null on failure.
177                 //
178                 public static Constant ChangeType (Location loc, Constant expr, Type type, EmitContext ec)
179                 {
180                         if (type == TypeManager.object_type)
181                                 return expr;
182
183                         bool fail;
184
185                         // from the null type to any reference-type.
186                         if (expr.Type == TypeManager.null_type && !type.IsValueType && !TypeManager.IsEnumType (type))
187                                 return NullLiteral.Null;
188                         
189                         if (!Expression.ImplicitConversionExists (ec, expr, type)){
190                                 Expression.Error_CannotConvertImplicit (loc, expr.Type, type);
191                                 return null;
192                           }
193
194                         // Special-case: The 0 literal can be converted to an enum value,
195                         // and ImplicitStandardConversionExists will return true in that case.
196                         if (expr.Type == TypeManager.int32_type && TypeManager.IsEnumType (type)){
197                                 if (expr is IntLiteral && ((IntLiteral) expr).Value == 0)
198                                         return new EnumConstant (expr, type);
199                         }
200
201                         object constant_value = TypeManager.ChangeType1 (expr.GetValue (), type, out fail);
202                         if (fail){
203                                 // Error_CannotImplicitConversion (loc, expr.Type, type);
204
205                                 //
206                                 // We should always catch the error before this is ever
207                                 // reached, by calling Convert.ImplicitStandardConversionExists
208                                 //
209                                 throw new Exception (
210                                                      String.Format ("LookupConstantValue: This should never be reached {0} {1}", expr.Type, type));
211                         }
212
213                         Constant retval;
214                         if (type == TypeManager.int32_type)
215                                 retval = new IntConstant ((int) constant_value);
216                         else if (type == TypeManager.uint32_type)
217                                 retval = new UIntConstant ((uint) constant_value);
218                         else if (type == TypeManager.int64_type)
219                                 retval = new LongConstant ((long) constant_value);
220                         else if (type == TypeManager.uint64_type)
221                                 retval = new ULongConstant ((ulong) constant_value);
222                         else if (type == TypeManager.float_type)
223                                 retval = new FloatConstant ((float) constant_value);
224                         else if (type == TypeManager.double_type)
225                                 retval = new DoubleConstant ((double) constant_value);
226                         else if (type == TypeManager.string_type)
227                                 retval = new StringConstant ((string) constant_value);
228                         else if (type == TypeManager.short_type)
229                                 retval = new ShortConstant ((short) constant_value);
230                         else if (type == TypeManager.ushort_type)
231                                 retval = new UShortConstant ((ushort) constant_value);
232                         else if (type == TypeManager.sbyte_type)
233                                 retval = new SByteConstant ((sbyte) constant_value);
234                         else if (type == TypeManager.byte_type)
235                                 retval = new ByteConstant ((byte) constant_value);
236                         else if (type == TypeManager.char_type)
237                                 retval = new CharConstant ((char) constant_value);
238                         else if (type == TypeManager.bool_type)
239                                 retval = new BoolConstant ((bool) constant_value);
240                         else if (type == TypeManager.decimal_type)
241                                 retval = new DecimalConstant ((decimal) constant_value);
242                         else
243                                  throw new Exception ("LookupConstantValue: Unhandled constant type: " + type);
244
245                         return retval;
246                 }
247                 
248                  /// <summary>
249                 ///  Looks up the value of a constant field. Defines it if it hasn't
250                 ///  already been. Similar to LookupEnumValue in spirit.
251                 /// </summary>
252                 public bool LookupConstantValue (out object value, EmitContext ec)
253                 {
254                         if (resolved) {
255                                 value = ConstantValue;
256                                 return true;
257                         }
258
259                         if (in_transit) {
260                                 Report.Error (110, Location,
261                                               "The evaluation of the constant value for `" +
262                                               Name + "' involves a circular definition.");
263                                 value = null;
264                                 return false;
265                         }
266
267                         in_transit = true;
268                         int errors = Report.Errors;
269
270                          //
271                         // We might have cleared Expr ourselves in a recursive definition
272                         //
273                         if (Expr == null){
274                                 value = null;
275                                 return false;
276                         }
277
278                         Expr = Expr.Resolve (ec);
279
280                         in_transit = false;
281
282                         if (Expr == null) {
283                                 if (errors == Report.Errors)
284                                         Report.Error (150, Location, "A constant value is expected");
285                                 value = null;
286                                 return false;
287                         }
288
289
290                         Constant ce = Expr as Constant;
291                         if (ce == null){
292                                 UnCheckedExpr un_expr = Expr as UnCheckedExpr;
293                                 CheckedExpr ch_expr = Expr as CheckedExpr;
294                                  if ((un_expr != null) && (un_expr.Expr is Constant))
295                                         Expr = un_expr.Expr;
296                                 else if ((ch_expr != null) && (ch_expr.Expr is Constant))
297                                         Expr = ch_expr.Expr;
298                                 //else if ((ec_expr != null) && (ec_expr.Child is Constant))
299                                  //       Expr = ec_expr.Child;
300                                 else if (Expr is ArrayCreation){
301                                         Report.Error (133, Location, "Arrays can not be constant");
302                                 } else {
303                                         if (errors == Report.Errors)
304                                                 Report.Error (150, Location, "A constant value is expected");
305                                         value = null;
306                                         return false;
307                                 }
308
309                                 ce = Expr as Constant;
310                         }
311
312                      //   if (MemberType != real_expr.Type) {
313                            if (type != Expr.Type) {
314
315                                 ce = ChangeType (Location, ce, type, ec);
316                                 if (ce == null){
317                                         value = null;
318                                         return false;
319                                 }
320                                 Expr = ce;
321                         }
322                         
323                         if (ce != null)
324                                 ConstantValue = ce.GetValue ();
325
326                         if (type.IsEnum){
327                                 //
328                                 // This sadly does not work for our user-defined enumerations types ;-(
329                                 //
330                                 try {
331                                         ConstantValue = System.Enum.ToObject (
332                                                 type, ConstantValue);
333                                 } catch (ArgumentException){
334                                         Report.Error (
335                                                 -16, Location,
336                                                 ".NET SDK 1.0 does not permit to create the constant "+
337                                                 " field from a user-defined enumeration");
338                                 }
339                         }
340
341                         if (ce is DecimalConstant) {
342                                 Decimal d = ((DecimalConstant)ce).Value;
343                                 int[] bits = Decimal.GetBits (d);
344                                 object[] args = new object[] { (byte)(bits [3] >> 16), (byte)(bits [3] >> 31), (uint)bits [2], (uint)bits [1], (uint)bits [0] };
345                                 CustomAttributeBuilder cab = new CustomAttributeBuilder (TypeManager.decimal_constant_attribute_ctor, args);
346                                 FieldBuilder.SetCustomAttribute (cab);
347                         }
348                         else{
349                                 FieldBuilder.SetConstant (ConstantValue);
350                         }
351
352                         if (!TypeManager.RegisterFieldValue (FieldBuilder, ConstantValue))
353                                 throw new Exception ("Cannot register const value");
354
355                         value = ConstantValue;
356                         resolved = true;
357                         return true;
358                 }
359
360
361
362                 
363                 
364                 
365                 /// <summary>
366                 ///  Emits the field value by evaluating the expression
367                 /// </summary>
368                 public void EmitConstant (TypeContainer parent)
369                 {
370                         EmitContext ec = new EmitContext (parent, Location, null, type, ModFlags);
371                         object value;
372                          LookupConstantValue (out value,ec);
373                         
374                         return;
375                 }
376                 
377                 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb)
378                 {
379                         FieldBuilder.SetCustomAttribute (cb);
380                 }
381                 
382         }
383 }