ecore.cs : Added support for Implicit numeric conversions
[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 namespace Mono.MonoBASIC {
21
22
23         using System;
24         using System.Reflection;
25         using System.Reflection.Emit;
26         using System.Collections;
27
28         public class Const : MemberCore {
29                 public Expression ConstantType;
30                 public Expression Expr;
31                 public FieldBuilder FieldBuilder;
32
33                 object ConstantValue = null;
34                 Type type;
35
36                 bool in_transit = false;
37
38                 public const int AllowedModifiers =
39                         Modifiers.PUBLIC |
40                         Modifiers.PROTECTED |
41                         Modifiers.INTERNAL |
42                         Modifiers.PRIVATE |
43                         Modifiers.SHADOWS;
44
45                 public Const (Expression constant_type, string name, Expression expr, int mod_flags,
46                               Attributes attrs, Location loc)
47                         : base (name, attrs, loc)
48                 {
49                         ConstantType = constant_type;
50                         Name = name;
51                         Expr = expr;
52                         ModFlags = Modifiers.Check (AllowedModifiers, mod_flags, Modifiers.PRIVATE, loc);
53                 }
54
55                 public override AttributeTargets AttributeTargets {
56                         get {
57                                 return AttributeTargets.Field;
58                         }
59                 }
60
61                 public FieldAttributes FieldAttr {
62                         get {
63                                 return FieldAttributes.Literal | FieldAttributes.Static |
64                                         Modifiers.FieldAttr (ModFlags) ;
65                         }
66                 }
67
68 #if DEBUG
69                 void dump_tree (Type t)
70                 {
71                         Console.WriteLine ("Dumping hierarchy");
72                         while (t != null){
73                                 Console.WriteLine ("   " + t.FullName + " " +
74                                         (t.GetType ().IsEnum ? "yes" : "no"));
75                                 t = t.BaseType;
76                         }
77                 }
78 #endif
79
80                 /// <summary>
81                 ///   Defines the constant in the @parent
82                 /// </summary>
83                 public override bool Define (TypeContainer parent)
84                 {
85                         type = parent.ResolveType (ConstantType, false, Location);
86
87                         if (type == null)
88                                 return false;
89
90                         if (!TypeManager.IsBuiltinType (type) &&
91                             (!type.IsSubclassOf (TypeManager.enum_type))) {
92                                 Report.Error (
93                                         30424, Location,
94                                         "Constant type is not valid (only system types are allowed)");
95                                 return false;
96                         }
97
98                         // if no type is declared expicitely 
99                         // set the expression type as the type of constant
100                         if (type == TypeManager.object_type){
101                                 if (Expr is IntLiteral)
102                                         type = TypeManager.int32_type;
103                                 else if (Expr is UIntLiteral)
104                                         type = TypeManager.uint32_type;
105                                 else if (Expr is LongLiteral)
106                                         type = TypeManager.int64_type;
107                                 else if (Expr is ULongLiteral)
108                                         type = TypeManager.uint64_type;
109                                 else if (Expr is FloatLiteral)
110                                         type = TypeManager.float_type;
111                                 else if (Expr is DoubleLiteral)
112                                         type = TypeManager.double_type;
113                                 else if (Expr is StringLiteral)
114                                         type = TypeManager.string_type;
115                                 else if (Expr is ShortLiteral)
116                                         type = TypeManager.short_type;
117                                 else if (Expr is UShortConstant)
118                                         type = TypeManager.ushort_type;
119                                 else if (Expr is SByteConstant)
120                                         type = TypeManager.sbyte_type;
121                                 else if (Expr is ByteConstant)
122                                         type = TypeManager.byte_type;
123                                 else if (Expr is CharConstant)
124                                         type = TypeManager.char_type;
125                                 else if (Expr is BoolConstant)
126                                         type = TypeManager.bool_type;
127                                 else if (Expr is DateConstant)
128                                         type = TypeManager.date_type;
129                         }
130                         Type ptype = parent.TypeBuilder.BaseType;
131
132                         if (ptype != null) {
133                                 MemberList list = TypeContainer.FindMembers (
134                                         ptype, MemberTypes.Field, BindingFlags.Public,
135                                         Type.FilterName, Name);
136                                 
137                                 if ((list.Count > 0) && ((ModFlags & Modifiers.SHADOWS) == 0))
138                                         Report.Warning (
139                                                 40004, 2, Location, 
140                                                 "Const '" + Name + "' should be declared " +
141                                                 "Shadows since the base type '" + ptype.Name + 
142                                                 "' has a Const with same name");
143                                 if (list.Count == 0) {
144                                         // if a member of module is not inherited from Object class
145                                         // can not be declared protected
146                                         if ((parent is Module) && ((ModFlags & Modifiers.PROTECTED) != 0))
147                                                 Report.Error (30593, Location,
148                                                         "'Const' inside a 'Module' can not be " +
149                                                         "declared as 'Protected'");
150
151                                         /*if ((ModFlags & Modifiers.NEW) != 0)
152                                                 WarningNotHiding (parent);*/
153                                 }
154                         } 
155                         /*else if ((ModFlags & Modifiers.NEW) != 0)
156                                 WarningNotHiding (parent);*/
157
158                         if ((parent is Struct) && ((ModFlags & Modifiers.PROTECTED) != 0))
159                                 Report.Error (30435, Location,
160                                         "'Const' inside a 'Structure' can not be " +
161                                         "declared as 'Protected'");
162
163                         FieldBuilder = parent.TypeBuilder.DefineField (Name, type, FieldAttr);
164
165                         TypeManager.RegisterConstant (FieldBuilder, this);
166
167                         return true;
168                 }
169
170                 /// <summary>
171                 ///  Looks up the value of a constant field. Defines it if it hasn't
172                 ///  already been. Similar to LookupEnumValue in spirit.
173                 /// </summary>
174                 public object LookupConstantValue (EmitContext ec)
175                 {
176                         if (ConstantValue != null)
177                                 return ConstantValue;
178
179                         if (in_transit) {
180                                 Report.Error (110, Location,
181                                               "The evaluation of the constant value for `" +
182                                               Name + "' involves a circular definition.");
183                                 return null;
184                         }
185
186                         in_transit = true;
187                         int errors = Report.Errors;
188
189                         Expr = Expr.Resolve (ec);
190
191                         in_transit = false;
192
193                         if (Expr == null) {
194                                 if (errors == Report.Errors)
195                                         Report.Error (30059, Location, "A constant value is expected");
196                                 return null;
197                         }
198
199                         if (!(Expr is Constant)) {
200                                 UnCheckedExpr un_expr = Expr as UnCheckedExpr;
201                                 CheckedExpr ch_expr = Expr as CheckedExpr;
202
203                                 if ((un_expr != null) && (un_expr.Expr is Constant))
204                                         Expr = un_expr.Expr;
205                                 else if ((ch_expr != null) && (ch_expr.Expr is Constant))
206                                         Expr = ch_expr.Expr;
207                                 else 
208                                 {
209                                         Report.Error (30059, Location, "A constant value is expected");
210                                         return null;
211                                 }
212                         }
213
214                         ConstantValue = ((Constant) Expr).GetValue ();
215
216                         if (type != Expr.Type) {
217                                 try {
218                                         ConstantValue = TypeManager.ChangeType (ConstantValue, type);
219                                 } catch {
220                                         Expression.Error_CannotConvertImplicit (Location, Expr.Type, type);
221                                         return null;
222                                 }
223
224                                 if (type == TypeManager.int32_type)
225                                         Expr = new IntConstant ((int) ConstantValue);
226                                 else if (type == TypeManager.uint32_type)
227                                         Expr = new UIntConstant ((uint) ConstantValue);
228                                 else if (type == TypeManager.int64_type)
229                                         Expr = new LongConstant ((long) ConstantValue);
230                                 else if (type == TypeManager.uint64_type)
231                                         Expr = new ULongConstant ((ulong) ConstantValue);
232                                 else if (type == TypeManager.float_type)
233                                         Expr = new FloatConstant ((float) ConstantValue);
234                                 else if (type == TypeManager.double_type)
235                                         Expr = new DoubleConstant ((double) ConstantValue);
236                                 else if (type == TypeManager.string_type)
237                                         Expr = new StringConstant ((string) ConstantValue);
238                                 else if (type == TypeManager.short_type)
239                                         Expr = new ShortConstant ((short) ConstantValue);
240                                 else if (type == TypeManager.ushort_type)
241                                         Expr = new UShortConstant ((ushort) ConstantValue);
242                                 else if (type == TypeManager.sbyte_type)
243                                         Expr = new SByteConstant ((sbyte) ConstantValue);
244                                 else if (type == TypeManager.byte_type)
245                                         Expr = new ByteConstant ((byte) ConstantValue);
246                                 else if (type == TypeManager.char_type)
247                                         Expr = new CharConstant ((char) ConstantValue);
248                                 else if (type == TypeManager.bool_type)
249                                         Expr = new BoolConstant ((bool) ConstantValue);
250                         }
251
252                         if (type.IsEnum){
253                                 //
254                                 // This sadly does not work for our user-defined enumerations types ;-(
255                                 //
256                                 try {
257                                         ConstantValue = System.Enum.ToObject (
258                                                 type, ConstantValue);
259                                 } catch (ArgumentException){
260                                         Report.Error (
261                                                 -16, Location,
262                                                 ".NET SDK 1.0 does not permit to create the constant "+
263                                                 " field from a user-defined enumeration");
264                                 }
265                         }
266
267                         FieldBuilder.SetConstant (ConstantValue);
268
269                         if (!TypeManager.RegisterFieldValue (FieldBuilder, ConstantValue))
270                                 return null;
271                         
272                         return ConstantValue;
273                 }
274                 
275                 
276                 /// <summary>
277                 ///  Emits the field value by evaluating the expression
278                 /// </summary>
279                 public void EmitConstant (TypeContainer parent)
280                 {
281                         EmitContext ec = new EmitContext (parent, Location, null, type, ModFlags);
282                         LookupConstantValue (ec);
283                         
284                         return;
285                 }
286                 
287                 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb)
288                 {
289                         FieldBuilder.SetCustomAttribute (cb);
290                 }
291                 
292         }
293 }