Add files for the 2 new errors.
[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                         EnumBuilder.DefineField ("value__", UnderlyingType,
108                                                  FieldAttributes.Public | FieldAttributes.SpecialName);
109
110                         RootContext.TypeManager.AddEnumType (EnumName, EnumBuilder, this);
111
112                         return;
113                 }
114
115                 bool IsValidEnumLiteral (Expression e)
116                 {
117                         if (!(e is Literal))
118                                 return false;
119
120                         if (e is IntLiteral || e is UIntLiteral || e is LongLiteral || e is ULongLiteral)
121                                 return true;
122                         else
123                                 return false;
124                 }
125
126                 object GetNextDefaultValue (object default_value)
127                 {
128                         if (UnderlyingType == TypeManager.int32_type) {
129                                 int i = (int) default_value;
130                                 
131                                 if (i < System.Int32.MaxValue)
132                                         return ++i;
133                                 else
134                                         return null;
135                         } else if (UnderlyingType == TypeManager.uint32_type) {
136                                 uint i = (uint) default_value;
137
138                                 if (i < System.UInt32.MaxValue)
139                                         return ++i;
140                                 else
141                                         return null;
142                         } else if (UnderlyingType == TypeManager.int64_type) {
143                                 long i = (long) default_value;
144
145                                 if (i < System.Int64.MaxValue)
146                                         return ++i;
147                                 else
148                                         return null;
149                         } else if (UnderlyingType == TypeManager.uint64_type) {
150                                 ulong i = (ulong) default_value;
151
152                                 if (i < System.UInt64.MaxValue)
153                                         return ++i;
154                                 else
155                                         return null;
156                         } else if (UnderlyingType == TypeManager.short_type) {
157                                 short i = (short) default_value;
158
159                                 if (i < System.Int16.MaxValue)
160                                         return ++i;
161                                 else
162                                         return null;
163                         } else if (UnderlyingType == TypeManager.ushort_type) {
164                                 ushort i = (ushort) default_value;
165
166                                 if (i < System.UInt16.MaxValue)
167                                         return ++i;
168                                 else
169                                         return null;
170                         } else if (UnderlyingType == TypeManager.byte_type) {
171                                 byte i = (byte) default_value;
172
173                                 if (i < System.Byte.MaxValue)
174                                         return ++i;
175                                 else
176                                         return null;
177                         } else if (UnderlyingType == TypeManager.sbyte_type) {
178                                 sbyte i = (sbyte) default_value;
179
180                                 if (i < System.SByte.MaxValue)
181                                         return ++i;
182                                 else
183                                         return null;
184                         }
185
186                         return null;
187                 }
188
189                 void error31 (Literal l, Location loc)
190                 {
191                         Report.Error (31, loc, "Constant value '" + l.AsString () +
192                                       "' cannot be converted" +
193                                       " to a " + TypeManager.CSharpName (UnderlyingType));
194                         return;
195                 }
196                 
197                 public void Populate (TypeContainer tc)
198                 {
199                         //
200                         // If there was an error during DefineEnum, return
201                         //
202                         if (EnumBuilder == null){
203                                 return;
204                         }
205                         
206                         EmitContext ec = new EmitContext (tc, null, UnderlyingType, ModFlags);
207                         
208                         object default_value = 0;
209                         
210                         FieldAttributes attr = FieldAttributes.Public | FieldAttributes.Static
211                                              | FieldAttributes.Literal;
212
213                         
214                         foreach (string name in ordered_enums) {
215                                 Expression e = this [name];
216                                 Location loc = (Location) member_to_location [name];
217
218                                 if (e != null) {
219                                         e = Expression.Reduce (ec, e);
220
221                                         if (IsValidEnumLiteral (e)) {
222                                                 Literal l = (Literal) e;
223                                                 default_value = l.GetValue ();
224
225                                                 if (default_value == null) {
226                                                         error31 (l, loc);
227                                                         return;
228                                                 }
229                                                 
230                                         } else {
231                                                 Report.Error (1008, loc,
232                                                   "Type byte, sbyte, short, ushort, int, uint, long, or ulong expected");
233                                                 return;
234                                         }
235                                 }
236                                 
237                                 FieldBuilder fb = EnumBuilder.DefineField (name, UnderlyingType, attr);
238
239                                 if (default_value == null) {
240                                         Report.Error (543, loc, "Enumerator value for '" + name + "' is too large to " +
241                                                       "fit in its type");
242                                         return;
243                                 }
244
245                                 try {
246                                         default_value = Convert.ChangeType (default_value, UnderlyingType);
247                                 } catch {
248                                         error31 ((Literal) e, loc);
249                                         return;
250                                 }
251
252                                 fb.SetConstant (default_value);
253                                 field_builders.Add (fb);
254
255                                 if (!TypeManager.RegisterField (fb, default_value))
256                                         return;
257
258                                 default_value = GetNextDefaultValue (default_value);
259                         }
260
261                         if (OptAttributes == null)
262                                 return;
263                         
264                         if (OptAttributes.AttributeSections == null)
265                                 return;
266                         
267                         foreach (AttributeSection asec in OptAttributes.AttributeSections) {
268                                 if (asec.Attributes == null)
269                                         continue;
270                                 
271                                 foreach (Attribute a in asec.Attributes) {
272                                         CustomAttributeBuilder cb = a.Resolve (ec);
273
274                                         if (cb == null)
275                                                 continue;
276                                         
277                                         EnumBuilder.SetCustomAttribute (cb);
278                                 }
279                         }
280                 }
281                 
282                 //
283                 // Hack around System.Reflection as found everywhere else
284                 //
285                 public MemberInfo [] FindMembers (MemberTypes mt, BindingFlags bf, MemberFilter filter, object criteria)
286                 {
287                         ArrayList members = new ArrayList ();
288
289                         if ((mt & MemberTypes.Field) != 0) {
290                                 foreach (FieldBuilder fb in field_builders)
291                                         if (filter (fb, criteria) == true)
292                                                 members.Add (fb);
293                         }
294
295                         int count = members.Count;
296
297                         if (count > 0) {
298                                 MemberInfo [] mi = new MemberInfo [count];
299                                 members.CopyTo (mi, 0);
300                                 return mi;
301                         }
302
303                         return null;
304                 }
305
306                 public void CloseEnum ()
307                 {
308                         EnumBuilder.CreateType ();
309                 }
310                 
311                 public ArrayList ValueNames {
312                         get {
313                                 return ordered_enums;
314                         }
315                 }
316
317                 public int ModFlags {
318                         get {
319                                 return mod_flags;
320                         }
321                 }
322                 
323                 // indexer
324                 public Expression this [string name] {
325                         get {
326                                 return (Expression) defined_names [name];
327                         }
328                 }
329         }
330 }