* expression.cs:
[mono.git] / mcs / mbas / enum.cs
1 //
2 // enum.cs: Enum handling.
3 //
4 // Author: Miguel de Icaza (miguel@gnu.org)
5 //         Ravi Pratap     (ravi@ximian.com)
6 //         Anirban Bhattacharjee (banirban@novell.com)
7 //         Jambunathan K (kjambunathan@novell.com)
8 //
9 // Licensed under the terms of the GNU GPL
10 //
11 // (C) 2001 Ximian, Inc (http://www.ximian.com)
12 //
13
14 using System;
15 using System.Collections;
16 using System.Reflection;
17 using System.Reflection.Emit;
18
19 namespace Mono.MonoBASIC {
20
21         public class EnumMember : MemberCore
22         {
23                 Enum parent_enum;
24                 Expression expr;
25                 int index;
26                 
27                 FieldBuilder builder;
28                 object enum_value;
29
30                 bool in_transit = false;
31                 FieldAttributes field_attrs = FieldAttributes.Public | FieldAttributes.Static
32                                                 | FieldAttributes.Literal;
33
34                 public EnumMember (Enum parent_enum, Expression expr, string name,
35                                    Location loc, Attributes attrs, int index):
36                         base (name, attrs, loc)
37                 {
38                         this.parent_enum = parent_enum;
39                         this.expr = expr;
40                         this.index = index;
41                 }
42
43                 public override void ApplyAttributeBuilder(Attribute a, CustomAttributeBuilder cb)
44                 {
45                         builder.SetCustomAttribute (cb);
46                 }
47
48                 public override AttributeTargets AttributeTargets {
49                         get {
50                                 return AttributeTargets.Field;
51                         }
52                 }
53
54                 public override bool Define (TypeContainer tc)
55                 {
56                         throw new NotImplementedException ();
57                 }
58
59                 public object GetValue ()
60                 {
61                         if (builder == null) 
62                                 DefineMember ();
63
64                         return enum_value;
65                 }
66
67                 public FieldBuilder DefineMember ()
68                 {
69                         if (builder != null)
70                                 return builder;
71
72                         DoDefineMember ();
73
74                         if (builder == null)
75                                 parent_enum.RemoveEnumMember (this.Name);
76
77                         return builder;
78                 }
79
80                 public FieldBuilder DoDefineMember ()
81                 {
82                         object default_value = null;
83                         Constant c = null;
84                         Type UnderlyingType = parent_enum.UnderlyingType;
85                         EmitContext ec = parent_enum.EmitContext;
86                         
87                         default_value = enum_value;
88                         
89                         if (in_transit) {
90                                 Report.Error (30500, Location, "The evaluation of the constant value for `" +
91                                               parent_enum.Name + "." + Name + "' involves a circular definition.");
92                                 return null;
93                         }
94
95                         //
96                         // So if the above doesn't happen, we have a member that is undefined
97                         // We now proceed to define it 
98                         //
99                         Expression val = expr;
100                         int idx = index;
101
102                         if (val == null) {
103                                 if (idx == 0)
104                                         default_value = 0;
105                                 else {
106                                         int i = idx - 1;
107                                         EnumMember em = parent_enum [i];
108
109                                         in_transit = true;
110                                         default_value = em.GetValue ();
111                                         in_transit = false;
112
113                                         if (default_value == null)
114                                                 return null;
115                                         
116                                         default_value = Enum.GetNextDefaultValue (default_value, UnderlyingType);
117                                 }
118                                 
119                         } else {
120                                 bool old = ec.InEnumContext;
121                                 ec.InEnumContext = true;
122                                 in_transit = true;
123                                 val = val.Resolve (ec);
124                                 in_transit = false;
125                                 ec.InEnumContext = old;
126
127                                 if (val == null)
128                                         return null;
129
130                                 if (! Enum.IsValidEnumConstant (val)) {
131                                         Report.Error (
132                                                 30650, Location,
133                                                 "Type byte, sbyte, short, ushort, int, uint, long, or " +
134                                                 "ulong expected (have: " + val + ")");
135                                         return null;
136                                 }
137
138                                 c = (Constant) val;
139                         
140                                 default_value = c.GetValue ();
141
142                                 if (default_value == null) {
143                                         Enum.Error_ConstantValueCannotBeConverted (c, Location, UnderlyingType);
144                                         return null;
145                                 }
146                         }
147
148                         builder = parent_enum.TypeBuilder.DefineField (Name, parent_enum.TypeBuilder, field_attrs);
149
150                         try {
151                                 //FXME: ChangeType is not the right thing to do. 
152                                 default_value = TypeManager.ChangeType (default_value, UnderlyingType);
153                         } catch {
154                                 Enum.Error_ConstantValueCannotBeConverted (c, Location, UnderlyingType);
155                                 return null;
156                         }
157
158                         enum_value = default_value;
159
160                         builder.SetConstant (enum_value);
161
162                         if (!TypeManager.RegisterFieldValue (builder, enum_value))
163                                 return null;
164
165                         if (OptAttributes != null)
166                                 OptAttributes.Emit (ec, this);
167
168                         return builder;
169                 }
170
171         }
172         
173
174         /// <summary>
175         ///   Enumeration container
176         /// </summary>
177         public class Enum : DeclSpace {
178                 ArrayList ordered_enums;
179                 public Expression BaseType;
180                 public Type UnderlyingType;
181                 ArrayList field_builders;
182                 
183                 public const int AllowedModifiers =
184                         Modifiers.NEW |
185                         Modifiers.PUBLIC |
186                         Modifiers.PROTECTED |
187                         Modifiers.INTERNAL |
188                         Modifiers.PRIVATE;
189
190                 EmitContext emit_context;
191
192                 public Enum (TypeContainer parent, Expression type, int mod_flags, string name, Attributes attrs, Location l)
193                         : base (parent, name, attrs, l)
194                 {
195                         this.BaseType = type;
196                         ModFlags = Modifiers.Check (AllowedModifiers, mod_flags,
197                                                     IsTopLevel ? Modifiers.INTERNAL : Modifiers.PUBLIC, l);
198
199                         ordered_enums = new ArrayList ();
200                         field_builders = new ArrayList ();
201                 }
202
203                 public override AttributeTargets AttributeTargets {
204                         get {
205                                 return AttributeTargets.Enum;
206                         }
207                 }
208
209                 /// <summary>
210                 ///   Adds @name to the enumeration space, with @expr
211                 ///   being its definition.  
212                 /// </summary>
213                 public AdditionResult AddEnumMember (string name, Expression expr, Location loc,
214                                                      Attributes opt_attrs)
215                 {
216                         int index;
217                         EnumMember em;
218                         
219                         if (defined_names.Contains (name))
220                                 return AdditionResult.NameExists;
221
222                         index = ordered_enums.Add (name);
223                         em = new EnumMember (this, expr, name, loc, opt_attrs, index);
224                         DefineName (name, em);
225
226                         return AdditionResult.Success;
227                 }
228
229                 public void RemoveEnumMember (string name)
230                 {
231                         defined_names.Remove (name);
232                 }
233
234                 public override TypeBuilder DefineType ()
235                 {
236                         if (TypeBuilder != null)
237                                 return TypeBuilder;
238
239                         emit_context = new EmitContext (Parent, this, Location, null,
240                                                           UnderlyingType, ModFlags, false);
241
242                         TypeAttributes attr = Modifiers.TypeAttr (ModFlags, IsTopLevel);
243
244                         attr |= TypeAttributes.Class | TypeAttributes.Sealed;
245
246                         UnderlyingType = ResolveType (BaseType, false, Location);
247
248                         if (UnderlyingType != TypeManager.int32_type &&
249                             UnderlyingType != TypeManager.uint32_type &&
250                             UnderlyingType != TypeManager.int64_type &&
251                             UnderlyingType != TypeManager.uint64_type &&
252                             UnderlyingType != TypeManager.short_type &&
253                             UnderlyingType != TypeManager.ushort_type &&
254                             UnderlyingType != TypeManager.byte_type  &&
255                             UnderlyingType != TypeManager.sbyte_type) {
256                                 Report.Error (30650, Location,
257                                               "Type byte, sbyte, short, ushort, int, uint, " +
258                                               "long, or ulong expected (got: " +
259                                               TypeManager.MonoBASIC_Name (UnderlyingType) + ")");
260                                 return null;
261                         }
262
263                         if (IsTopLevel) {
264                                 ModuleBuilder builder = CodeGen.ModuleBuilder;
265
266                                 TypeBuilder = builder.DefineType (Name, attr, TypeManager.enum_type);
267                         } else {
268                                 TypeBuilder builder = Parent.TypeBuilder;
269
270                                 TypeBuilder = builder.DefineNestedType (
271                                         Basename, attr, TypeManager.enum_type);
272                         }
273
274                         TypeBuilder.DefineField ("value__", UnderlyingType,
275                                                  FieldAttributes.Public | FieldAttributes.SpecialName
276                                                  | FieldAttributes.RTSpecialName);
277
278                         TypeManager.AddEnumType (Name, TypeBuilder, this);
279
280                         return TypeBuilder;
281                 }
282
283                 public static bool IsValidEnumConstant (Expression e)
284                 {
285                         if (!(e is Constant))
286                                 return false;
287
288                         if (e is IntConstant || e is UIntConstant || e is LongConstant ||
289                             e is ByteConstant || e is SByteConstant || e is ShortConstant ||
290                             e is UShortConstant || e is ULongConstant || e is EnumConstant)
291                                 return true;
292                         else
293                                 return false;
294                 }
295
296                 static public object GetNextDefaultValue (object default_value, Type UnderlyingType)
297                 {
298                         if (UnderlyingType == TypeManager.int32_type) {
299                                 int i = (int) default_value;
300                                 
301                                 if (i < System.Int32.MaxValue)
302                                         return ++i;
303                                 else
304                                         return null;
305                         } else if (UnderlyingType == TypeManager.uint32_type) {
306                                 uint i = (uint) default_value;
307
308                                 if (i < System.UInt32.MaxValue)
309                                         return ++i;
310                                 else
311                                         return null;
312                         } else if (UnderlyingType == TypeManager.int64_type) {
313                                 long i = (long) default_value;
314
315                                 if (i < System.Int64.MaxValue)
316                                         return ++i;
317                                 else
318                                         return null;
319                         } else if (UnderlyingType == TypeManager.uint64_type) {
320                                 ulong i = (ulong) default_value;
321
322                                 if (i < System.UInt64.MaxValue)
323                                         return ++i;
324                                 else
325                                         return null;
326                         } else if (UnderlyingType == TypeManager.short_type) {
327                                 short i = (short) default_value;
328
329                                 if (i < System.Int16.MaxValue)
330                                         return ++i;
331                                 else
332                                         return null;
333                         } else if (UnderlyingType == TypeManager.ushort_type) {
334                                 ushort i = (ushort) default_value;
335
336                                 if (i < System.UInt16.MaxValue)
337                                         return ++i;
338                                 else
339                                         return null;
340                         } else if (UnderlyingType == TypeManager.byte_type) {
341                                 byte i = (byte) default_value;
342
343                                 if (i < System.Byte.MaxValue)
344                                         return ++i;
345                                 else
346                                         return null;
347                         } else if (UnderlyingType == TypeManager.sbyte_type) {
348                                 sbyte i = (sbyte) default_value;
349
350                                 if (i < System.SByte.MaxValue)
351                                         return ++i;
352                                 else
353                                         return null;
354                         }
355
356                         return null;
357                 }
358
359                 public static void Error_ConstantValueCannotBeConverted (object val, Location loc, Type UnderlyingType)
360                 {
361                         if (val is Constant)
362                                 Report.Error (30439, loc, "Constant value '" + ((Constant) val).AsString () +
363                                               "' cannot be converted" +
364                                               " to a " + TypeManager.MonoBASIC_Name (UnderlyingType));
365                         else 
366                                 Report.Error (30439, loc, "Constant value '" + val +
367                                               "' cannot be converted" +
368                                               " to a " + TypeManager.MonoBASIC_Name (UnderlyingType));
369                         return;
370                 }
371
372                 /// <summary>
373                 ///  This is used to lookup the value of an enum member. If the member is undefined,
374                 ///  it attempts to define it and return its value
375                 /// </summary>
376                 public object LookupEnumValue (string name)
377                 {
378                         EnumMember em;
379
380                         // first check whether the requested name is there
381                         // in the member list of enum
382
383                         em = this [name];
384
385                         if (em == null)
386                                 return null;
387                         
388                         name = em.Name;
389                         FieldBuilder fb = em.DefineMember ();
390                         
391                         if (fb == null) {
392                                 return null;
393                         } 
394
395                         if (! field_builders.Contains (fb)) {
396                                 field_builders.Add (fb);
397                         }
398
399                         return em.GetValue ();
400                 }
401
402                 public override bool DefineMembers (TypeContainer parent)
403                 {
404                         return true;
405                 }
406                 
407                 public override bool Define (TypeContainer parent)
408                 {
409                         if (TypeBuilder == null)
410                                 return false;
411                         /*
412                         EmitContext ec = new EmitContext (parent, this, Location, null,
413                                                           UnderlyingType, ModFlags, false);
414                         */
415                         foreach (string name in ordered_enums) {
416                                 EnumMember em = this [name];
417                                 FieldBuilder fb = em.DefineMember ();
418
419                                 if (fb == null) {
420                                         return false;
421                                 } 
422
423                                 if (!field_builders.Contains (fb)) {
424                                         field_builders.Add (fb);
425                                 }
426                         }
427
428                         if (OptAttributes != null)
429                                 OptAttributes.Emit (EmitContext, this);
430                         
431                         return true;
432                 }
433                 
434                 //
435                 // IMemberFinder
436                 //
437                 public override MemberList FindMembers (MemberTypes mt, BindingFlags bf,
438                                                         MemberFilter filter, object criteria)
439                 {
440                         ArrayList members = new ArrayList ();
441
442                         if ((mt & MemberTypes.Field) != 0) {
443                                 
444                                 if (criteria is string){
445                                         LookupEnumValue ((string) criteria);
446                                 }
447                                 
448                                 foreach (FieldBuilder fb in field_builders)
449                                         if (filter (fb, criteria) == true)
450                                                 members.Add (fb);
451                         }
452
453                         return new MemberList (members);
454                 }
455
456                 public override MemberCache MemberCache {
457                         get {
458                                 return null;
459                         }
460                 }
461
462                 public ArrayList ValueNames {
463                         get {
464                                 return ordered_enums;
465                         }
466                 }
467
468                 // indexer
469                 public EnumMember this [string name] {
470                         get {
471                                 EnumMember em = (EnumMember) defined_names [name];
472
473                                 if (em != null)
474                                         return em;
475
476                                 name = name.ToLower();
477                                 foreach (string nm in ordered_enums) {
478                                         if (nm.ToLower() == name) {
479                                                 em = (EnumMember) defined_names [name];
480                                                 break;
481                                         }
482                                 }
483
484                                 return em;
485                         }
486                 }
487
488                 public EnumMember this[int mem_index] {
489                         get {
490                                 string mem_name = (string) ordered_enums [mem_index];;
491                                 return (EnumMember) defined_names[mem_name];
492                         }
493                 }
494
495                 public EmitContext EmitContext {
496                         get {
497                                 return emit_context;
498                         }
499                 }
500         }
501 }