2 // enum.cs: Enum handling.
4 // Author: Miguel de Icaza (miguel@gnu.org)
5 // Ravi Pratap (ravi@ximian.com)
6 // Anirban Bhattacharjee (banirban@novell.com)
8 // Licensed under the terms of the GNU GPL
10 // (C) 2001 Ximian, Inc (http://www.ximian.com)
14 using System.Collections;
15 using System.Reflection;
16 using System.Reflection.Emit;
18 namespace Mono.MonoBASIC {
21 /// Enumeration container
23 public class Enum : DeclSpace {
24 ArrayList ordered_enums;
26 public Expression BaseType;
27 public Attributes OptAttributes;
29 public Type UnderlyingType;
31 Hashtable member_to_location;
32 Hashtable member_to_attributes;
35 // This is for members that have been defined
37 Hashtable member_to_value;
40 // This is used to mark members we're currently defining
44 ArrayList field_builders;
46 public const int AllowedModifiers =
53 public Enum (TypeContainer parent, Expression type, int mod_flags, string name, Attributes attrs, Location l)
54 : base (parent, name, l)
57 ModFlags = Modifiers.Check (AllowedModifiers, mod_flags,
58 IsTopLevel ? Modifiers.INTERNAL : Modifiers.PUBLIC, l);
59 OptAttributes = attrs;
61 ordered_enums = new ArrayList ();
62 member_to_location = new Hashtable ();
63 member_to_value = new Hashtable ();
64 in_transit = new Hashtable ();
65 field_builders = new ArrayList ();
69 /// Adds @name to the enumeration space, with @expr
70 /// being its definition.
72 public AdditionResult AddEnumMember (string name, Expression expr, Location loc,
75 if (defined_names.Contains (name))
76 return AdditionResult.NameExists;
78 DefineName (name, expr);
80 ordered_enums.Add (name);
81 member_to_location.Add (name, loc);
83 if (member_to_attributes == null)
84 member_to_attributes = new Hashtable ();
86 member_to_attributes.Add (name, opt_attrs);
88 return AdditionResult.Success;
92 // This is used by corlib compilation: we map from our
93 // type to a type that is consumable by the DefineField
95 Type MapToInternalType (Type t)
97 if (t == TypeManager.int32_type)
99 if (t == TypeManager.int64_type)
100 return typeof (long);
101 if (t == TypeManager.uint32_type)
102 return typeof (uint);
103 if (t == TypeManager.uint64_type)
104 return typeof (ulong);
105 if (t == TypeManager.float_type)
106 return typeof (float);
107 if (t == TypeManager.double_type)
108 return typeof (double);
109 if (t == TypeManager.byte_type)
110 return typeof (byte);
111 if (t == TypeManager.sbyte_type)
112 return typeof (sbyte);
113 if (t == TypeManager.char_type)
114 return typeof (char);
115 if (t == TypeManager.short_type)
116 return typeof (short);
117 if (t == TypeManager.ushort_type)
118 return typeof (ushort);
120 throw new Exception ();
123 public override TypeBuilder DefineType ()
125 if (TypeBuilder != null)
128 TypeAttributes attr = Modifiers.TypeAttr (ModFlags, IsTopLevel);
130 attr |= TypeAttributes.Class | TypeAttributes.Sealed;
132 UnderlyingType = ResolveType (BaseType, false, Location);
134 if (UnderlyingType != TypeManager.int32_type &&
135 UnderlyingType != TypeManager.uint32_type &&
136 UnderlyingType != TypeManager.int64_type &&
137 UnderlyingType != TypeManager.uint64_type &&
138 UnderlyingType != TypeManager.short_type &&
139 UnderlyingType != TypeManager.ushort_type &&
140 UnderlyingType != TypeManager.byte_type &&
141 UnderlyingType != TypeManager.sbyte_type) {
142 Report.Error (30650, Location,
143 "Type byte, sbyte, short, ushort, int, uint, " +
144 "long, or ulong expected (got: " +
145 TypeManager.MonoBASIC_Name (UnderlyingType) + ")");
150 ModuleBuilder builder = CodeGen.ModuleBuilder;
152 TypeBuilder = builder.DefineType (Name, attr, TypeManager.enum_type);
154 TypeBuilder builder = Parent.TypeBuilder;
156 TypeBuilder = builder.DefineNestedType (
157 Basename, attr, TypeManager.enum_type);
161 // Call MapToInternalType for corlib
163 TypeBuilder.DefineField ("value__", UnderlyingType,
164 FieldAttributes.Public | FieldAttributes.SpecialName
165 | FieldAttributes.RTSpecialName);
167 TypeManager.AddEnumType (Name, TypeBuilder, this);
172 bool IsValidEnumConstant (Expression e)
174 if (!(e is Constant))
177 if (e is IntConstant || e is UIntConstant || e is LongConstant ||
178 e is ByteConstant || e is SByteConstant || e is ShortConstant ||
179 e is UShortConstant || e is ULongConstant || e is EnumConstant)
185 object GetNextDefaultValue (object default_value)
187 if (UnderlyingType == TypeManager.int32_type) {
188 int i = (int) default_value;
190 if (i < System.Int32.MaxValue)
194 } else if (UnderlyingType == TypeManager.uint32_type) {
195 uint i = (uint) default_value;
197 if (i < System.UInt32.MaxValue)
201 } else if (UnderlyingType == TypeManager.int64_type) {
202 long i = (long) default_value;
204 if (i < System.Int64.MaxValue)
208 } else if (UnderlyingType == TypeManager.uint64_type) {
209 ulong i = (ulong) default_value;
211 if (i < System.UInt64.MaxValue)
215 } else if (UnderlyingType == TypeManager.short_type) {
216 short i = (short) default_value;
218 if (i < System.Int16.MaxValue)
222 } else if (UnderlyingType == TypeManager.ushort_type) {
223 ushort i = (ushort) default_value;
225 if (i < System.UInt16.MaxValue)
229 } else if (UnderlyingType == TypeManager.byte_type) {
230 byte i = (byte) default_value;
232 if (i < System.Byte.MaxValue)
236 } else if (UnderlyingType == TypeManager.sbyte_type) {
237 sbyte i = (sbyte) default_value;
239 if (i < System.SByte.MaxValue)
248 void Error_ConstantValueCannotBeConverted (object val, Location loc)
251 Report.Error (30439, loc, "Constant value '" + ((Constant) val).AsString () +
252 "' cannot be converted" +
253 " to a " + TypeManager.MonoBASIC_Name (UnderlyingType));
255 Report.Error (30439, loc, "Constant value '" + val +
256 "' cannot be converted" +
257 " to a " + TypeManager.MonoBASIC_Name (UnderlyingType));
262 /// Determines if a standard implicit conversion exists from
263 /// expr_type to target_type
265 public static bool ImplicitConversionExists (Type expr_type, Type target_type)
267 expr_type = TypeManager.TypeToCoreType (expr_type);
269 if (expr_type == TypeManager.void_type)
272 if (expr_type == target_type)
275 // First numeric conversions
277 if (expr_type == TypeManager.sbyte_type){
279 // From sbyte to short, int, long, float, double.
281 if ((target_type == TypeManager.int32_type) ||
282 (target_type == TypeManager.int64_type) ||
283 (target_type == TypeManager.double_type) ||
284 (target_type == TypeManager.float_type) ||
285 (target_type == TypeManager.short_type) ||
286 (target_type == TypeManager.decimal_type))
289 } else if (expr_type == TypeManager.byte_type){
291 // From byte to short, ushort, int, uint, long, ulong, float, double
293 if ((target_type == TypeManager.short_type) ||
294 (target_type == TypeManager.ushort_type) ||
295 (target_type == TypeManager.int32_type) ||
296 (target_type == TypeManager.uint32_type) ||
297 (target_type == TypeManager.uint64_type) ||
298 (target_type == TypeManager.int64_type) ||
299 (target_type == TypeManager.float_type) ||
300 (target_type == TypeManager.double_type) ||
301 (target_type == TypeManager.decimal_type))
304 } else if (expr_type == TypeManager.short_type){
306 // From short to int, long, float, double
308 if ((target_type == TypeManager.int32_type) ||
309 (target_type == TypeManager.int64_type) ||
310 (target_type == TypeManager.double_type) ||
311 (target_type == TypeManager.float_type) ||
312 (target_type == TypeManager.decimal_type))
315 } else if (expr_type == TypeManager.ushort_type){
317 // From ushort to int, uint, long, ulong, float, double
319 if ((target_type == TypeManager.uint32_type) ||
320 (target_type == TypeManager.uint64_type) ||
321 (target_type == TypeManager.int32_type) ||
322 (target_type == TypeManager.int64_type) ||
323 (target_type == TypeManager.double_type) ||
324 (target_type == TypeManager.float_type) ||
325 (target_type == TypeManager.decimal_type))
328 } else if (expr_type == TypeManager.int32_type){
330 // From int to long, float, double
332 if ((target_type == TypeManager.int64_type) ||
333 (target_type == TypeManager.double_type) ||
334 (target_type == TypeManager.float_type) ||
335 (target_type == TypeManager.decimal_type))
338 } else if (expr_type == TypeManager.uint32_type){
340 // From uint to long, ulong, float, double
342 if ((target_type == TypeManager.int64_type) ||
343 (target_type == TypeManager.uint64_type) ||
344 (target_type == TypeManager.double_type) ||
345 (target_type == TypeManager.float_type) ||
346 (target_type == TypeManager.decimal_type))
349 } else if ((expr_type == TypeManager.uint64_type) ||
350 (expr_type == TypeManager.int64_type)) {
352 // From long/ulong to float, double
354 if ((target_type == TypeManager.double_type) ||
355 (target_type == TypeManager.float_type) ||
356 (target_type == TypeManager.decimal_type))
359 } else if (expr_type == TypeManager.char_type){
361 // From char to ushort, int, uint, long, ulong, float, double
363 if ((target_type == TypeManager.ushort_type) ||
364 (target_type == TypeManager.int32_type) ||
365 (target_type == TypeManager.uint32_type) ||
366 (target_type == TypeManager.uint64_type) ||
367 (target_type == TypeManager.int64_type) ||
368 (target_type == TypeManager.float_type) ||
369 (target_type == TypeManager.double_type) ||
370 (target_type == TypeManager.decimal_type))
373 } else if (expr_type == TypeManager.float_type){
377 if (target_type == TypeManager.double_type)
385 /// This is used to lookup the value of an enum member. If the member is undefined,
386 /// it attempts to define it and return its value
388 public object LookupEnumValue (EmitContext ec, string name, Location loc)
390 object default_value = null;
392 TypeContainer parent = ec.TypeContainer;
394 // first check whether the requested name is there
395 // in the member list of enum
396 if (!(ordered_enums.Contains(name)))
397 Report.Error (30456, loc,
398 name + " is not found in member list of enum " + this.Name);
400 default_value = member_to_value [name];
402 if (default_value != null)
403 return default_value;
406 // This may happen if we're calling a method in System.Enum, for instance
409 if (!defined_names.Contains (name))
412 if (in_transit.Contains (name)) {
413 Report.Error (110, loc, "The evaluation of the constant value for `" +
414 Name + "." + name + "' involves a circular definition.");
419 // So if the above doesn't happen, we have a member that is undefined
420 // We now proceed to define it
422 Expression val = this [name];
423 int idx = ordered_enums.IndexOf (name);
427 //int idx = ordered_enums.IndexOf (name);
432 for (int i = 0; i < idx; ++i) {
433 string n = (string) ordered_enums [i];
434 Location m_loc = (Mono.MonoBASIC.Location)
435 member_to_location [n];
436 in_transit.Add (name, true);
437 default_value = LookupEnumValue (ec, n, m_loc);
438 in_transit.Remove (name);
439 if (default_value == null)
443 default_value = GetNextDefaultValue (default_value);
447 // check for any cyclic dependency
448 if (val is Mono.MonoBASIC.SimpleName) {
449 int var_idx = ordered_enums.IndexOf (val.ToString());
452 Report.Error(30500, loc,
453 "The evaluation of the constant value for `" +
454 Name + "." + name + "' involves a circular definition");
456 default_value = member_to_value [val.ToString()];
459 bool old = ec.InEnumContext;
460 ec.InEnumContext = true;
461 in_transit.Add (name, true);
462 val = val.Resolve (ec);
463 in_transit.Remove (name);
464 ec.InEnumContext = old;
469 if (!IsValidEnumConstant (val)) {
472 "Type byte, sbyte, short, ushort, int, uint, long, or " +
473 "ulong expected (have: " + val + ")");
479 default_value = c.GetValue ();
482 if (default_value == null) {
483 Error_ConstantValueCannotBeConverted (c, loc);
487 if (val is EnumConstant) {
488 Type etype = TypeManager.EnumToUnderlying (c.Type);
490 if ( (!ImplicitConversionExists (etype, UnderlyingType)) &&
491 (!Expression.NarrowingConversionExists (ec, val, UnderlyingType)) ){
492 Expression.Error_CannotConvertImplicit (
493 loc, c.Type, UnderlyingType);
499 FieldAttributes attr = FieldAttributes.Public | FieldAttributes.Static
500 | FieldAttributes.Literal;
502 FieldBuilder fb = TypeBuilder.DefineField (name, TypeBuilder, attr);
505 default_value = TypeManager.ChangeType (default_value, UnderlyingType);
507 Error_ConstantValueCannotBeConverted (c, loc);
511 fb.SetConstant (default_value);
512 field_builders.Add (fb);
513 member_to_value [name] = default_value;
515 if (!TypeManager.RegisterFieldValue (fb, default_value))
519 // Now apply attributes
521 Attribute.ApplyAttributes (ec, fb, fb, (Attributes) member_to_attributes [name], loc);
523 return default_value;
526 public override bool DefineMembers (TypeContainer parent)
531 public override bool Define (TypeContainer parent)
534 // If there was an error during DefineEnum, return
536 if (TypeBuilder == null)
539 EmitContext ec = new EmitContext (parent, this, Location, null,
540 UnderlyingType, ModFlags, false);
542 object default_value = 0;
544 foreach (string name in ordered_enums) {
545 if (member_to_value.Contains (name))
548 Location loc = (Mono.MonoBASIC.Location) member_to_location [name];
550 if (this [name] != null) {
551 default_value = LookupEnumValue (ec, name, loc);
553 if (default_value == null)
556 FieldAttributes attr = FieldAttributes.Public | FieldAttributes.Static
557 | FieldAttributes.Literal;
559 FieldBuilder fb = TypeBuilder.DefineField (name, TypeBuilder, attr);
561 if (default_value == null) {
562 Report.Error (30439, loc, "Enumerator value for '" + name + "' is too large to " +
568 default_value = TypeManager.ChangeType (default_value, UnderlyingType);
570 Error_ConstantValueCannotBeConverted (default_value, loc);
574 fb.SetConstant (default_value);
575 field_builders.Add (fb);
576 member_to_value [name] = default_value;
578 if (!TypeManager.RegisterFieldValue (fb, default_value))
582 // Now apply attributes
584 Attribute.ApplyAttributes (ec, fb, fb, (Attributes) member_to_attributes [name], loc);
587 default_value = GetNextDefaultValue (default_value);
590 Attribute.ApplyAttributes (ec, TypeBuilder, this, OptAttributes, Location);
597 public override MemberList FindMembers (MemberTypes mt, BindingFlags bf,
598 MemberFilter filter, object criteria)
600 ArrayList members = new ArrayList ();
602 if ((mt & MemberTypes.Field) != 0) {
603 foreach (FieldBuilder fb in field_builders)
604 if (filter (fb, criteria) == true)
608 return new MemberList (members);
611 public override MemberCache MemberCache {
617 public ArrayList ValueNames {
619 return ordered_enums;
624 public Expression this [string name] {
626 return (Expression) defined_names [name];