2002-06-17 Miguel de Icaza <miguel@ximian.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 namespace Mono.CSharp {
21
22         using System;
23         using System.Reflection;
24         using System.Reflection.Emit;
25         using System.Collections;
26
27         public class Const : MemberCore {
28                 public readonly string ConstantType;
29                 public Expression Expr;
30                 public Attributes  OptAttributes;
31                 public FieldBuilder FieldBuilder;
32
33                 object ConstantValue = null;
34                 Type type;
35
36                 public const int AllowedModifiers =
37                         Modifiers.NEW |
38                         Modifiers.PUBLIC |
39                         Modifiers.PROTECTED |
40                         Modifiers.INTERNAL |
41                         Modifiers.PRIVATE;
42
43                 public Const (string constant_type, string name, Expression expr, int mod_flags,
44                               Attributes attrs, Location loc)
45                         : base (name, loc)
46                 {
47                         ConstantType = constant_type;
48                         Name = name;
49                         Expr = expr;
50                         ModFlags = Modifiers.Check (AllowedModifiers, mod_flags, Modifiers.PRIVATE, loc);
51                         OptAttributes = attrs;
52                 }
53
54                 public FieldAttributes FieldAttr {
55                         get {
56                                 return FieldAttributes.Literal | FieldAttributes.Static |
57                                         Modifiers.FieldAttr (ModFlags) ;
58                         }
59                 }
60
61 #if DEBUG
62                 void dump_tree (Type t)
63                 {
64                         Console.WriteLine ("Dumping hierarchy");
65                         while (t != null){
66                                 Console.WriteLine ("   " + t.FullName + " " +
67                                         (t.GetType ().IsEnum ? "yes" : "no"));
68                                 t = t.BaseType;
69                         }
70                 }
71 #endif
72
73                 /// <summary>
74                 ///   Defines the constant in the @parent
75                 /// </summary>
76                 public override bool Define (TypeContainer parent)
77                 {
78                         type = RootContext.LookupType (parent, ConstantType, true, Location);
79
80                         if (type == null)
81                                 return false;
82
83                         if (!TypeManager.IsBuiltinType (type) &&
84                             (!type.IsSubclassOf (TypeManager.enum_type))) {
85                                 Report.Error (
86                                         -3, Location,
87                                         "Constant type is not valid (only system types are allowed)");
88                                 return false;
89                         }
90
91                         Type ptype = parent.TypeBuilder.BaseType;
92
93                         if (ptype != null) {
94                                 MemberInfo [] mi = TypeContainer.FindMembers (
95                                         ptype, MemberTypes.Field, BindingFlags.Public,
96                                         Type.FilterName, Name);
97                                 
98                                 if (mi == null || mi.Length == 0)
99                                         if ((ModFlags & Modifiers.NEW) != 0)
100                                                 WarningNotHiding (parent);
101
102                         } else if ((ModFlags & Modifiers.NEW) != 0)
103                                 WarningNotHiding (parent);
104
105                         FieldBuilder = parent.TypeBuilder.DefineField (Name, type, FieldAttr);
106
107                         TypeManager.RegisterConstant (FieldBuilder, this);
108
109                         return true;
110                 }
111
112                 /// <summary>
113                 ///  Looks up the value of a constant field. Defines it if it hasn't
114                 ///  already been. Similar to LookupEnumValue in spirit.
115                 /// </summary>
116                 public object LookupConstantValue (EmitContext ec)
117                 {
118                         if (ConstantValue != null)
119                                 return ConstantValue;
120
121                         Expr = Expr.Resolve (ec);
122
123                         if (Expr == null) {
124                                 Report.Error (150, Location, "A constant value is expected");
125                                 return null;
126                         }
127
128                         if (!(Expr is Constant)) {
129                                 Report.Error (150, Location, "A constant value is expected");
130                                 return null;
131                         }
132
133                         ConstantValue = ((Constant) Expr).GetValue ();
134
135                         if (type != Expr.Type) {
136                                 try {
137                                         ConstantValue = TypeManager.ChangeType (ConstantValue, type);
138                                 } catch {
139                                         Expression.Error_CannotConvertImplicit (Location, Expr.Type, type);
140                                         return null;
141                                 }
142
143                                 if (type == TypeManager.int32_type)
144                                         Expr = new IntConstant ((int) ConstantValue);
145                                 else if (type == TypeManager.uint32_type)
146                                         Expr = new UIntConstant ((uint) ConstantValue);
147                                 else if (type == TypeManager.int64_type)
148                                         Expr = new LongConstant ((long) ConstantValue);
149                                 else if (type == TypeManager.uint64_type)
150                                         Expr = new ULongConstant ((ulong) ConstantValue);
151                                 else if (type == TypeManager.float_type)
152                                         Expr = new FloatConstant ((float) ConstantValue);
153                                 else if (type == TypeManager.double_type)
154                                         Expr = new DoubleConstant ((double) ConstantValue);
155                                 else if (type == TypeManager.string_type)
156                                         Expr = new StringConstant ((string) ConstantValue);
157                                 else if (type == TypeManager.short_type)
158                                         Expr = new ShortConstant ((short) ConstantValue);
159                                 else if (type == TypeManager.ushort_type)
160                                         Expr = new UShortConstant ((ushort) ConstantValue);
161                                 else if (type == TypeManager.sbyte_type)
162                                         Expr = new SByteConstant ((sbyte) ConstantValue);
163                                 else if (type == TypeManager.byte_type)
164                                         Expr = new ByteConstant ((byte) ConstantValue);
165                                 else if (type == TypeManager.char_type)
166                                         Expr = new CharConstant ((char) ConstantValue);
167                                 else if (type == TypeManager.bool_type)
168                                         Expr = new BoolConstant ((bool) ConstantValue);
169                         }
170
171                         if (type.IsEnum){
172                                 //
173                                 // This sadly does not work for our user-defined enumerations types ;-(
174                                 //
175                                 try {
176                                         ConstantValue = System.Enum.ToObject (
177                                                 type, ConstantValue);
178                                 } catch (ArgumentException){
179                                         Report.Error (
180                                                 -16, Location,
181                                                 ".NET SDK 1.0 does not permit to create the constant "+
182                                                 " field from a user-defined enumeration");
183                                 }
184                         }
185
186                         FieldBuilder.SetConstant (ConstantValue);
187
188                         if (!TypeManager.RegisterFieldValue (FieldBuilder, ConstantValue))
189                                 return null;
190
191                         return ConstantValue;
192                 }
193                 
194                 
195                 /// <summary>
196                 ///  Emits the field value by evaluating the expression
197                 /// </summary>
198                 public void EmitConstant (TypeContainer parent)
199                 {
200                         EmitContext ec = new EmitContext (parent, Location, null, type, ModFlags);
201                         LookupConstantValue (ec);
202                         
203                         return;
204                 }
205         }
206 }
207
208