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