2001-11-11 Ravi Pratap <ravi@ximian.com>
[mono.git] / mcs / mcs / enum.cs
1 //
2 // enum.cs: Enum handling.
3 //
4 // Author: Miguel de Icaza (miguel@gnu.org)
5 //
6 // Licensed under the terms of the GNU GPL
7 //
8 // (C) 2001 Ximian, Inc (http://www.ximian.com)
9 //
10
11 using System;
12 using System.Collections;
13 using System.Reflection;
14 using System.Reflection.Emit;
15
16 namespace CIR {
17
18         public class Enum : DeclSpace {
19
20                 ArrayList ordered_enums;
21                 public readonly string BaseType;
22                 public readonly string EnumName;
23                 int mod_flags;
24                 public TypeBuilder EnumBuilder;
25                 public Attributes  OptAttributes;
26
27                 Type UnderlyingType;
28
29                 public readonly RootContext RootContext;
30
31                 Hashtable member_to_location;
32                 ArrayList field_builders;
33
34                 public const int AllowedModifiers =
35                         Modifiers.NEW |
36                         Modifiers.PUBLIC |
37                         Modifiers.PROTECTED |
38                         Modifiers.INTERNAL |
39                         Modifiers.PRIVATE;
40
41                 public Enum (RootContext rc, string type, int mod_flags, string name, Attributes attrs, Location l)
42                         : base (name, l)
43                 {
44                         RootContext = rc;
45                         this.BaseType = type;
46                         this.EnumName = name;
47                         this.mod_flags = Modifiers.Check (AllowedModifiers, mod_flags, Modifiers.PUBLIC);
48                         OptAttributes = attrs;
49                         ordered_enums = new ArrayList ();
50                         member_to_location = new Hashtable ();
51                         field_builders = new ArrayList ();
52                 }
53
54                 // <summary>
55                 //   Adds @name to the enumeration space, with @expr
56                 //   being its definition.  
57                 // </summary>
58                 public AdditionResult AddEnumMember (string name, Expression expr, Location loc)
59                 {
60                         if (defined_names.Contains (name))
61                                 return AdditionResult.NameExists;
62
63                         DefineName (name, expr);
64
65                         ordered_enums.Add (name);
66                         member_to_location.Add (name, loc);
67                         
68                         return AdditionResult.Success;
69                 }
70
71                 public void DefineEnum (object parent_builder)
72                 {
73                         TypeAttributes attr = TypeAttributes.Class | TypeAttributes.Sealed;
74
75                         UnderlyingType = RootContext.TypeManager.LookupType (BaseType);
76
77                         if (UnderlyingType != TypeManager.int32_type && UnderlyingType != TypeManager.uint32_type &&
78                             UnderlyingType != TypeManager.int64_type && UnderlyingType != TypeManager.uint64_type &&
79                             UnderlyingType != TypeManager.short_type && UnderlyingType != TypeManager.ushort_type &&
80                             UnderlyingType != TypeManager.byte_type  && UnderlyingType != TypeManager.sbyte_type) {
81                                 Report.Error (1008, Location,
82                                               "Type byte, sbyte, short, ushort, int, uint, long, or ulong expected");
83                                 return;
84                         }
85
86                         if (parent_builder is ModuleBuilder) {
87                                 ModuleBuilder builder = (ModuleBuilder) parent_builder;
88
89                                 if ((ModFlags & Modifiers.PUBLIC) != 0)
90                                         attr |= TypeAttributes.Public;
91                                 else
92                                         attr |= TypeAttributes.NotPublic;
93                                 
94                                 EnumBuilder = builder.DefineType (EnumName, attr, TypeManager.enum_type);
95
96                         } else {
97                                 TypeBuilder builder = (TypeBuilder) parent_builder;
98
99                                 if ((ModFlags & Modifiers.PUBLIC) != 0)
100                                         attr |= TypeAttributes.NestedPublic;
101                                 else
102                                         attr |= TypeAttributes.NestedPrivate;
103                                 
104                                 EnumBuilder = builder.DefineNestedType (EnumName, attr, TypeManager.enum_type);
105                         }
106
107
108                         EnumBuilder.DefineField ("value__", UnderlyingType,
109                                                  FieldAttributes.Public | FieldAttributes.SpecialName);
110                         
111                         RootContext.TypeManager.AddEnumType (EnumName, EnumBuilder, this);
112                 }
113
114                 bool IsValidEnumLiteral (Expression e)
115                 {
116                         if (!(e is Literal))
117                                 return false;
118
119                         if (e is IntLiteral || e is UIntLiteral || e is LongLiteral || e is ULongLiteral)
120                                 return true;
121                         else
122                                 return false;
123                 }
124
125                 object GetNextDefaultValue (object default_value)
126                 {
127                         if (UnderlyingType == TypeManager.int32_type) {
128                                 int i = (int) default_value;
129                                 
130                                 if (i < System.Int32.MaxValue)
131                                         return ++i;
132                                 else
133                                         return null;
134                         } else if (UnderlyingType == TypeManager.uint32_type) {
135                                 uint i = (uint) default_value;
136
137                                 if (i < System.UInt32.MaxValue)
138                                         return ++i;
139                                 else
140                                         return null;
141                         } else if (UnderlyingType == TypeManager.int64_type) {
142                                 long i = (long) default_value;
143
144                                 if (i < System.Int64.MaxValue)
145                                         return ++i;
146                                 else
147                                         return null;
148                         } else if (UnderlyingType == TypeManager.uint64_type) {
149                                 ulong i = (ulong) default_value;
150
151                                 if (i < System.UInt64.MaxValue)
152                                         return ++i;
153                                 else
154                                         return null;
155                         } else if (UnderlyingType == TypeManager.short_type) {
156                                 short i = (short) default_value;
157
158                                 if (i < System.Int16.MaxValue)
159                                         return ++i;
160                                 else
161                                         return null;
162                         } else if (UnderlyingType == TypeManager.ushort_type) {
163                                 ushort i = (ushort) default_value;
164
165                                 if (i < System.UInt16.MaxValue)
166                                         return ++i;
167                                 else
168                                         return null;
169                         } else if (UnderlyingType == TypeManager.byte_type) {
170                                 byte i = (byte) default_value;
171
172                                 if (i < System.Byte.MaxValue)
173                                         return ++i;
174                                 else
175                                         return null;
176                         } else if (UnderlyingType == TypeManager.sbyte_type) {
177                                 sbyte i = (sbyte) default_value;
178
179                                 if (i < System.SByte.MaxValue)
180                                         return ++i;
181                                 else
182                                         return null;
183                         }
184
185                         return null;
186                 }
187
188                 void error31 (Literal l, Location loc)
189                 {
190                         Report.Error (31, loc, "Constant value '" + l.AsString () +
191                                       "' cannot be converted" +
192                                       " to a " + TypeManager.CSharpName (UnderlyingType));
193                         return;
194                 }
195                 
196                 public void Populate (TypeContainer tc)
197                 {
198                         EmitContext ec = new EmitContext (tc, null, UnderlyingType, ModFlags);
199                         
200                         object default_value = 0;
201                         
202                         FieldAttributes attr = FieldAttributes.Public | FieldAttributes.Static
203                                              | FieldAttributes.Literal;
204
205                         
206                         foreach (string name in ordered_enums) {
207                                 Expression e = this [name];
208                                 Location loc = (Location) member_to_location [name];
209
210                                 if (e != null) {
211                                         e = Expression.Reduce (ec, e);
212
213                                         if (IsValidEnumLiteral (e)) {
214                                                 Literal l = (Literal) e;
215                                                 default_value = l.GetValue ();
216
217                                                 if (default_value == null) {
218                                                         error31 (l, loc);
219                                                         return;
220                                                 }
221                                                 
222                                         } else {
223                                                 Report.Error (1008, loc,
224                                                   "Type byte, sbyte, short, ushort, int, uint, long, or ulong expected");
225                                                 return;
226                                         }
227                                 }
228                                 
229                                 FieldBuilder fb = EnumBuilder.DefineField (name, UnderlyingType, attr);
230
231                                 if (default_value == null) {
232                                         Report.Error (543, loc, "Enumerator value for '" + name + "' is too large to " +
233                                                       "fit in its type");
234                                         return;
235                                 }
236
237                                 try {
238                                         default_value = Convert.ChangeType (default_value, UnderlyingType);
239                                 } catch {
240                                         error31 ((Literal) e, loc);
241                                         return;
242                                 }
243                                 
244                                 fb.SetConstant (default_value);
245                                 field_builders.Add (fb);
246
247                                 if (!TypeManager.RegisterField (fb, default_value))
248                                         return;
249
250                                 default_value = GetNextDefaultValue (default_value);
251                         }
252
253                         if (OptAttributes == null)
254                                 return;
255                         
256                         if (OptAttributes.AttributeSections == null)
257                                 return;
258                         
259                         foreach (AttributeSection asec in OptAttributes.AttributeSections) {
260                                 if (asec.Attributes == null)
261                                         continue;
262                                 
263                                 foreach (Attribute a in asec.Attributes) {
264                                         CustomAttributeBuilder cb = a.Resolve (ec);
265
266                                         if (cb == null)
267                                                 continue;
268                                         
269                                         EnumBuilder.SetCustomAttribute (cb);
270                                 }
271                         }
272                 }
273                 
274                 //
275                 // Hack around System.Reflection as found everywhere else
276                 //
277                 public MemberInfo [] FindMembers (MemberTypes mt, BindingFlags bf, MemberFilter filter, object criteria)
278                 {
279                         ArrayList members = new ArrayList ();
280
281                         if ((mt & MemberTypes.Field) != 0) {
282                                 foreach (FieldBuilder fb in field_builders)
283                                         if (filter (fb, criteria) == true)
284                                                 members.Add (fb);
285                         }
286
287                         int count = members.Count;
288
289                         if (count > 0) {
290                                 MemberInfo [] mi = new MemberInfo [count];
291                                 members.CopyTo (mi, 0);
292                                 return mi;
293                         }
294
295                         return null;
296                 }
297
298                 public void CloseEnum ()
299                 {
300                         EnumBuilder.CreateType ();
301                 }
302                 
303                 public ArrayList ValueNames {
304                         get {
305                                 return ordered_enums;
306                         }
307                 }
308
309                 public int ModFlags {
310                         get {
311                                 return mod_flags;
312                         }
313                 }
314                 
315                 // indexer
316                 public Expression this [string name] {
317                         get {
318                                 return (Expression) defined_names [name];
319                         }
320                 }
321         }
322 }