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
;
28 public Type UnderlyingType
;
30 Hashtable member_to_location
;
31 Hashtable member_to_attributes
;
34 // This is for members that have been defined
36 Hashtable member_to_value
;
39 // This is used to mark members we're currently defining
43 ArrayList field_builders
;
45 public const int AllowedModifiers
=
52 public Enum (TypeContainer parent
, Expression type
, int mod_flags
, string name
, Attributes attrs
, Location l
)
53 : base (parent
, name
, attrs
, l
)
56 ModFlags
= Modifiers
.Check (AllowedModifiers
, mod_flags
,
57 IsTopLevel
? Modifiers
.INTERNAL
: Modifiers
.PUBLIC
, l
);
59 ordered_enums
= new ArrayList ();
60 member_to_location
= new Hashtable ();
61 member_to_value
= new Hashtable ();
62 in_transit
= new Hashtable ();
63 field_builders
= new ArrayList ();
66 public override AttributeTargets AttributeTargets
{
68 return AttributeTargets
.Enum
;
73 /// Adds @name to the enumeration space, with @expr
74 /// being its definition.
76 public AdditionResult
AddEnumMember (string name
, Expression expr
, Location loc
,
79 if (defined_names
.Contains (name
))
80 return AdditionResult
.NameExists
;
82 DefineName (name
, expr
);
84 ordered_enums
.Add (name
);
85 member_to_location
.Add (name
, loc
);
87 if (member_to_attributes
== null)
88 member_to_attributes
= new Hashtable ();
90 member_to_attributes
.Add (name
, opt_attrs
);
92 return AdditionResult
.Success
;
96 // This is used by corlib compilation: we map from our
97 // type to a type that is consumable by the DefineField
99 Type
MapToInternalType (Type t
)
101 if (t
== TypeManager
.int32_type
)
103 if (t
== TypeManager
.int64_type
)
104 return typeof (long);
105 if (t
== TypeManager
.uint32_type
)
106 return typeof (uint);
107 if (t
== TypeManager
.uint64_type
)
108 return typeof (ulong);
109 if (t
== TypeManager
.float_type
)
110 return typeof (float);
111 if (t
== TypeManager
.double_type
)
112 return typeof (double);
113 if (t
== TypeManager
.byte_type
)
114 return typeof (byte);
115 if (t
== TypeManager
.sbyte_type
)
116 return typeof (sbyte);
117 if (t
== TypeManager
.char_type
)
118 return typeof (char);
119 if (t
== TypeManager
.short_type
)
120 return typeof (short);
121 if (t
== TypeManager
.ushort_type
)
122 return typeof (ushort);
124 throw new Exception ();
127 public override TypeBuilder
DefineType ()
129 if (TypeBuilder
!= null)
132 TypeAttributes attr
= Modifiers
.TypeAttr (ModFlags
, IsTopLevel
);
134 attr
|= TypeAttributes
.Class
| TypeAttributes
.Sealed
;
136 UnderlyingType
= ResolveType (BaseType
, false, Location
);
138 if (UnderlyingType
!= TypeManager
.int32_type
&&
139 UnderlyingType
!= TypeManager
.uint32_type
&&
140 UnderlyingType
!= TypeManager
.int64_type
&&
141 UnderlyingType
!= TypeManager
.uint64_type
&&
142 UnderlyingType
!= TypeManager
.short_type
&&
143 UnderlyingType
!= TypeManager
.ushort_type
&&
144 UnderlyingType
!= TypeManager
.byte_type
&&
145 UnderlyingType
!= TypeManager
.sbyte_type
) {
146 Report
.Error (30650, Location
,
147 "Type byte, sbyte, short, ushort, int, uint, " +
148 "long, or ulong expected (got: " +
149 TypeManager
.MonoBASIC_Name (UnderlyingType
) + ")");
154 ModuleBuilder builder
= CodeGen
.ModuleBuilder
;
156 TypeBuilder
= builder
.DefineType (Name
, attr
, TypeManager
.enum_type
);
158 TypeBuilder builder
= Parent
.TypeBuilder
;
160 TypeBuilder
= builder
.DefineNestedType (
161 Basename
, attr
, TypeManager
.enum_type
);
165 // Call MapToInternalType for corlib
167 TypeBuilder
.DefineField ("value__", UnderlyingType
,
168 FieldAttributes
.Public
| FieldAttributes
.SpecialName
169 | FieldAttributes
.RTSpecialName
);
171 TypeManager
.AddEnumType (Name
, TypeBuilder
, this);
176 bool IsValidEnumConstant (Expression e
)
178 if (!(e
is Constant
))
181 if (e
is IntConstant
|| e
is UIntConstant
|| e
is LongConstant
||
182 e
is ByteConstant
|| e
is SByteConstant
|| e
is ShortConstant
||
183 e
is UShortConstant
|| e
is ULongConstant
|| e
is EnumConstant
)
189 object GetNextDefaultValue (object default_value
)
191 if (UnderlyingType
== TypeManager
.int32_type
) {
192 int i
= (int) default_value
;
194 if (i
< System
.Int32
.MaxValue
)
198 } else if (UnderlyingType
== TypeManager
.uint32_type
) {
199 uint i
= (uint) default_value
;
201 if (i
< System
.UInt32
.MaxValue
)
205 } else if (UnderlyingType
== TypeManager
.int64_type
) {
206 long i
= (long) default_value
;
208 if (i
< System
.Int64
.MaxValue
)
212 } else if (UnderlyingType
== TypeManager
.uint64_type
) {
213 ulong i
= (ulong) default_value
;
215 if (i
< System
.UInt64
.MaxValue
)
219 } else if (UnderlyingType
== TypeManager
.short_type
) {
220 short i
= (short) default_value
;
222 if (i
< System
.Int16
.MaxValue
)
226 } else if (UnderlyingType
== TypeManager
.ushort_type
) {
227 ushort i
= (ushort) default_value
;
229 if (i
< System
.UInt16
.MaxValue
)
233 } else if (UnderlyingType
== TypeManager
.byte_type
) {
234 byte i
= (byte) default_value
;
236 if (i
< System
.Byte
.MaxValue
)
240 } else if (UnderlyingType
== TypeManager
.sbyte_type
) {
241 sbyte i
= (sbyte) default_value
;
243 if (i
< System
.SByte
.MaxValue
)
252 void Error_ConstantValueCannotBeConverted (object val
, Location loc
)
255 Report
.Error (30439, loc
, "Constant value '" + ((Constant
) val
).AsString () +
256 "' cannot be converted" +
257 " to a " + TypeManager
.MonoBASIC_Name (UnderlyingType
));
259 Report
.Error (30439, loc
, "Constant value '" + val
+
260 "' cannot be converted" +
261 " to a " + TypeManager
.MonoBASIC_Name (UnderlyingType
));
266 /// Determines if a standard implicit conversion exists from
267 /// expr_type to target_type
269 public static bool ImplicitConversionExists (Type expr_type
, Type target_type
)
271 expr_type
= TypeManager
.TypeToCoreType (expr_type
);
273 if (expr_type
== TypeManager
.void_type
)
276 if (expr_type
== target_type
)
279 // First numeric conversions
281 if (expr_type
== TypeManager
.sbyte_type
){
283 // From sbyte to short, int, long, float, double.
285 if ((target_type
== TypeManager
.int32_type
) ||
286 (target_type
== TypeManager
.int64_type
) ||
287 (target_type
== TypeManager
.double_type
) ||
288 (target_type
== TypeManager
.float_type
) ||
289 (target_type
== TypeManager
.short_type
) ||
290 (target_type
== TypeManager
.decimal_type
))
293 } else if (expr_type
== TypeManager
.byte_type
){
295 // From byte to short, ushort, int, uint, long, ulong, float, double
297 if ((target_type
== TypeManager
.short_type
) ||
298 (target_type
== TypeManager
.ushort_type
) ||
299 (target_type
== TypeManager
.int32_type
) ||
300 (target_type
== TypeManager
.uint32_type
) ||
301 (target_type
== TypeManager
.uint64_type
) ||
302 (target_type
== TypeManager
.int64_type
) ||
303 (target_type
== TypeManager
.float_type
) ||
304 (target_type
== TypeManager
.double_type
) ||
305 (target_type
== TypeManager
.decimal_type
))
308 } else if (expr_type
== TypeManager
.short_type
){
310 // From short to int, long, float, double
312 if ((target_type
== TypeManager
.int32_type
) ||
313 (target_type
== TypeManager
.int64_type
) ||
314 (target_type
== TypeManager
.double_type
) ||
315 (target_type
== TypeManager
.float_type
) ||
316 (target_type
== TypeManager
.decimal_type
))
319 } else if (expr_type
== TypeManager
.ushort_type
){
321 // From ushort to int, uint, long, ulong, float, double
323 if ((target_type
== TypeManager
.uint32_type
) ||
324 (target_type
== TypeManager
.uint64_type
) ||
325 (target_type
== TypeManager
.int32_type
) ||
326 (target_type
== TypeManager
.int64_type
) ||
327 (target_type
== TypeManager
.double_type
) ||
328 (target_type
== TypeManager
.float_type
) ||
329 (target_type
== TypeManager
.decimal_type
))
332 } else if (expr_type
== TypeManager
.int32_type
){
334 // From int to long, float, double
336 if ((target_type
== TypeManager
.int64_type
) ||
337 (target_type
== TypeManager
.double_type
) ||
338 (target_type
== TypeManager
.float_type
) ||
339 (target_type
== TypeManager
.decimal_type
))
342 } else if (expr_type
== TypeManager
.uint32_type
){
344 // From uint to long, ulong, float, double
346 if ((target_type
== TypeManager
.int64_type
) ||
347 (target_type
== TypeManager
.uint64_type
) ||
348 (target_type
== TypeManager
.double_type
) ||
349 (target_type
== TypeManager
.float_type
) ||
350 (target_type
== TypeManager
.decimal_type
))
353 } else if ((expr_type
== TypeManager
.uint64_type
) ||
354 (expr_type
== TypeManager
.int64_type
)) {
356 // From long/ulong to float, double
358 if ((target_type
== TypeManager
.double_type
) ||
359 (target_type
== TypeManager
.float_type
) ||
360 (target_type
== TypeManager
.decimal_type
))
363 } else if (expr_type
== TypeManager
.char_type
){
365 // From char to ushort, int, uint, long, ulong, float, double
367 if ((target_type
== TypeManager
.ushort_type
) ||
368 (target_type
== TypeManager
.int32_type
) ||
369 (target_type
== TypeManager
.uint32_type
) ||
370 (target_type
== TypeManager
.uint64_type
) ||
371 (target_type
== TypeManager
.int64_type
) ||
372 (target_type
== TypeManager
.float_type
) ||
373 (target_type
== TypeManager
.double_type
) ||
374 (target_type
== TypeManager
.decimal_type
))
377 } else if (expr_type
== TypeManager
.float_type
){
381 if (target_type
== TypeManager
.double_type
)
389 /// This is used to lookup the value of an enum member. If the member is undefined,
390 /// it attempts to define it and return its value
392 public object LookupEnumValue (EmitContext ec
, string name
, Location loc
)
394 object default_value
= null;
396 TypeContainer parent
= ec
.TypeContainer
;
398 // first check whether the requested name is there
399 // in the member list of enum
401 name
= name
.ToLower();
402 foreach (string nm
in ordered_enums
) {
403 if (nm
.ToLower() == name
) {
411 Report
.Error (30456, loc
,
412 name
+ " is not found in member list of enum " + this.Name
);
414 default_value
= member_to_value
[name
];
416 if (default_value
!= null)
417 return default_value
;
420 // This may happen if we're calling a method in System.Enum, for instance
423 if (!defined_names
.Contains (name
))
426 if (in_transit
.Contains (name
)) {
427 Report
.Error (110, loc
, "The evaluation of the constant value for `" +
428 Name
+ "." + name
+ "' involves a circular definition.");
433 // So if the above doesn't happen, we have a member that is undefined
434 // We now proceed to define it
436 Expression val
= this [name
];
437 int idx
= ordered_enums
.IndexOf (name
);
441 //int idx = ordered_enums.IndexOf (name);
446 for (int i
= 0; i
< idx
; ++i
) {
447 string n
= (string) ordered_enums
[i
];
448 Location m_loc
= (Mono
.MonoBASIC
.Location
)
449 member_to_location
[n
];
450 in_transit
.Add (name
, true);
451 default_value
= LookupEnumValue (ec
, n
, m_loc
);
452 in_transit
.Remove (name
);
453 if (default_value
== null)
457 default_value
= GetNextDefaultValue (default_value
);
461 // check for any cyclic dependency
462 if (val
is Mono
.MonoBASIC
.SimpleName
) {
463 int var_idx
= ordered_enums
.IndexOf (val
.ToString());
466 Report
.Error(30500, loc
,
467 "The evaluation of the constant value for `" +
468 Name
+ "." + name
+ "' involves a circular definition");
470 default_value
= member_to_value
[val
.ToString()];
473 bool old
= ec
.InEnumContext
;
474 ec
.InEnumContext
= true;
475 in_transit
.Add (name
, true);
476 val
= val
.Resolve (ec
);
477 in_transit
.Remove (name
);
478 ec
.InEnumContext
= old
;
483 if (!IsValidEnumConstant (val
)) {
486 "Type byte, sbyte, short, ushort, int, uint, long, or " +
487 "ulong expected (have: " + val
+ ")");
493 default_value
= c
.GetValue ();
496 if (default_value
== null) {
497 Error_ConstantValueCannotBeConverted (c
, loc
);
501 if (val
is EnumConstant
) {
502 Type etype
= TypeManager
.EnumToUnderlying (c
.Type
);
504 if ( (!ImplicitConversionExists (etype
, UnderlyingType
)) &&
505 (!Expression
.NarrowingConversionExists (ec
, val
, UnderlyingType
)) ){
506 Expression
.Error_CannotConvertImplicit (
507 loc
, c
.Type
, UnderlyingType
);
513 FieldAttributes attr
= FieldAttributes
.Public
| FieldAttributes
.Static
514 | FieldAttributes
.Literal
;
516 FieldBuilder fb
= TypeBuilder
.DefineField (name
, TypeBuilder
, attr
);
519 default_value
= TypeManager
.ChangeType (default_value
, UnderlyingType
);
521 Error_ConstantValueCannotBeConverted (c
, loc
);
525 fb
.SetConstant (default_value
);
526 field_builders
.Add (fb
);
527 member_to_value
[name
] = default_value
;
529 if (!TypeManager
.RegisterFieldValue (fb
, default_value
))
533 // Now apply attributes
535 Attribute
.ApplyAttributes (ec
, fb
, fb
, (Attributes
) member_to_attributes
[name
], loc
);
537 return default_value
;
540 public override bool DefineMembers (TypeContainer parent
)
545 public override bool Define (TypeContainer parent
)
548 // If there was an error during DefineEnum, return
550 if (TypeBuilder
== null)
553 EmitContext ec
= new EmitContext (parent
, this, Location
, null,
554 UnderlyingType
, ModFlags
, false);
556 object default_value
= 0;
558 foreach (string name
in ordered_enums
) {
559 if (member_to_value
.Contains (name
))
562 Location loc
= (Mono
.MonoBASIC
.Location
) member_to_location
[name
];
564 if (this [name
] != null) {
565 default_value
= LookupEnumValue (ec
, name
, loc
);
567 if (default_value
== null)
570 FieldAttributes attr
= FieldAttributes
.Public
| FieldAttributes
.Static
571 | FieldAttributes
.Literal
;
573 FieldBuilder fb
= TypeBuilder
.DefineField (name
, TypeBuilder
, attr
);
575 if (default_value
== null) {
576 Report
.Error (30439, loc
, "Enumerator value for '" + name
+ "' is too large to " +
582 default_value
= TypeManager
.ChangeType (default_value
, UnderlyingType
);
584 Error_ConstantValueCannotBeConverted (default_value
, loc
);
588 fb
.SetConstant (default_value
);
589 field_builders
.Add (fb
);
590 member_to_value
[name
] = default_value
;
592 if (!TypeManager
.RegisterFieldValue (fb
, default_value
))
596 // Now apply attributes
598 Attribute
.ApplyAttributes (ec
, fb
, fb
, (Attributes
) member_to_attributes
[name
], loc
);
601 default_value
= GetNextDefaultValue (default_value
);
604 Attribute
.ApplyAttributes (ec
, TypeBuilder
, this, OptAttributes
, Location
);
611 public override MemberList
FindMembers (MemberTypes mt
, BindingFlags bf
,
612 MemberFilter filter
, object criteria
)
614 ArrayList members
= new ArrayList ();
616 if ((mt
& MemberTypes
.Field
) != 0) {
617 foreach (FieldBuilder fb
in field_builders
)
618 if (filter (fb
, criteria
) == true)
622 return new MemberList (members
);
625 public override MemberCache MemberCache
{
631 public ArrayList ValueNames
{
633 return ordered_enums
;
638 public Expression
this [string name
] {
640 return (Expression
) defined_names
[name
];