2005-01-26 Martin Baulig <martin@ximian.com>
[mono.git] / mcs / mbas / enum.cs
index c361d4445e9d4b0097479317c53fad869c20395c..b7eaae1ea8d08f1432bde90c15afc68ae4996584 100644 (file)
@@ -3,6 +3,8 @@
 //
 // Author: Miguel de Icaza (miguel@gnu.org)
 //         Ravi Pratap     (ravi@ximian.com)
+//         Anirban Bhattacharjee (banirban@novell.com)
+//         Jambunathan K (kjambunathan@novell.com)
 //
 // Licensed under the terms of the GNU GPL
 //
@@ -14,26 +16,168 @@ using System.Collections;
 using System.Reflection;
 using System.Reflection.Emit;
 
-namespace Mono.CSharp {
+namespace Mono.MonoBASIC {
+
+       public class EnumMember : MemberCore
+       {
+               Enum parent_enum;
+               Expression expr;
+               int index;
+               
+               FieldBuilder builder;
+               object enum_value;
+
+               bool in_transit = false;
+               FieldAttributes field_attrs = FieldAttributes.Public | FieldAttributes.Static
+                                               | FieldAttributes.Literal;
+
+               public EnumMember (Enum parent_enum, Expression expr, string name,
+                                  Location loc, Attributes attrs, int index):
+                       base (name, attrs, loc)
+               {
+                       this.parent_enum = parent_enum;
+                       this.expr = expr;
+                       this.index = index;
+               }
+
+               public override void ApplyAttributeBuilder(Attribute a, CustomAttributeBuilder cb)
+               {
+                       builder.SetCustomAttribute (cb);
+               }
+
+               public override AttributeTargets AttributeTargets {
+                       get {
+                               return AttributeTargets.Field;
+                       }
+               }
+
+               public override bool Define (TypeContainer tc)
+               {
+                       throw new NotImplementedException ();
+               }
+
+               public object GetValue ()
+               {
+                       if (builder == null) 
+                               DefineMember ();
+
+                       return enum_value;
+               }
+
+               public FieldBuilder DefineMember ()
+               {
+                       if (builder != null)
+                               return builder;
+
+                       DoDefineMember ();
+
+                       if (builder == null)
+                               parent_enum.RemoveEnumMember (this.Name);
+
+                       return builder;
+               }
+
+               public FieldBuilder DoDefineMember ()
+               {
+                       object default_value = null;
+                       Constant c = null;
+                       Type UnderlyingType = parent_enum.UnderlyingType;
+                       EmitContext ec = parent_enum.EmitContext;
+                       
+                       default_value = enum_value;
+                       
+                       if (in_transit) {
+                               Report.Error (30500, Location, "The evaluation of the constant value for `" +
+                                             parent_enum.Name + "." + Name + "' involves a circular definition.");
+                               return null;
+                       }
+
+                       //
+                       // So if the above doesn't happen, we have a member that is undefined
+                       // We now proceed to define it 
+                       //
+                       Expression val = expr;
+                       int idx = index;
+
+                       if (val == null) {
+                               if (idx == 0)
+                                       default_value = 0;
+                               else {
+                                       int i = idx - 1;
+                                       EnumMember em = parent_enum [i];
+
+                                       in_transit = true;
+                                       default_value = em.GetValue ();
+                                       in_transit = false;
+
+                                       if (default_value == null)
+                                               return null;
+                                       
+                                       default_value = Enum.GetNextDefaultValue (default_value, UnderlyingType);
+                               }
+                               
+                       } else {
+                               bool old = ec.InEnumContext;
+                               ec.InEnumContext = true;
+                               in_transit = true;
+                               val = val.Resolve (ec);
+                               in_transit = false;
+                               ec.InEnumContext = old;
+
+                               if (val == null)
+                                       return null;
+
+                               if (! Enum.IsValidEnumConstant (val)) {
+                                       Report.Error (
+                                               30650, Location,
+                                               "Type byte, sbyte, short, ushort, int, uint, long, or " +
+                                               "ulong expected (have: " + val + ")");
+                                       return null;
+                               }
+
+                               c = (Constant) val;
+                       
+                               default_value = c.GetValue ();
+
+                               if (default_value == null) {
+                                       Enum.Error_ConstantValueCannotBeConverted (c, Location, UnderlyingType);
+                                       return null;
+                               }
+                       }
+
+                       builder = parent_enum.TypeBuilder.DefineField (Name, parent_enum.TypeBuilder, field_attrs);
+
+                       try {
+                               //FXME: ChangeType is not the right thing to do. 
+                               default_value = TypeManager.ChangeType (default_value, UnderlyingType);
+                       } catch {
+                               Enum.Error_ConstantValueCannotBeConverted (c, Location, UnderlyingType);
+                               return null;
+                       }
+
+                       enum_value = default_value;
+
+                       builder.SetConstant (enum_value);
+
+                       if (!TypeManager.RegisterFieldValue (builder, enum_value))
+                               return null;
+
+                       if (OptAttributes != null)
+                               OptAttributes.Emit (ec, this);
+
+                       return builder;
+               }
+
+       }
+       
 
        /// <summary>
        ///   Enumeration container
        /// </summary>
        public class Enum : DeclSpace {
-
                ArrayList ordered_enums;
-               public readonly string BaseType;
-               public Attributes  OptAttributes;
-               
+               public Expression BaseType;
                public Type UnderlyingType;
-
-               Hashtable member_to_location;
-
-               //
-               // This is for members that have been defined
-               //
-               Hashtable member_to_value;
-               
                ArrayList field_builders;
                
                public const int AllowedModifiers =
@@ -43,77 +187,64 @@ namespace Mono.CSharp {
                        Modifiers.INTERNAL |
                        Modifiers.PRIVATE;
 
-               public Enum (TypeContainer parent, string type, int mod_flags, string name, Attributes attrs, Location l)
-                       : base (parent, name, l)
+               EmitContext emit_context;
+
+               public Enum (TypeContainer parent, Expression type, int mod_flags, string name, Attributes attrs, Location l)
+                       : base (parent, name, attrs, l)
                {
                        this.BaseType = type;
-                       ModFlags = Modifiers.Check (AllowedModifiers, mod_flags, Modifiers.PUBLIC, l);
-                       OptAttributes = attrs;
+                       ModFlags = Modifiers.Check (AllowedModifiers, mod_flags,
+                                                   IsTopLevel ? Modifiers.INTERNAL : Modifiers.PUBLIC, l);
 
                        ordered_enums = new ArrayList ();
-                       member_to_location = new Hashtable ();
-                       member_to_value = new Hashtable ();
                        field_builders = new ArrayList ();
                }
 
+               public override AttributeTargets AttributeTargets {
+                       get {
+                               return AttributeTargets.Enum;
+                       }
+               }
+
                /// <summary>
                ///   Adds @name to the enumeration space, with @expr
                ///   being its definition.  
                /// </summary>
-               public AdditionResult AddEnumMember (string name, Expression expr, Location loc)
+               public AdditionResult AddEnumMember (string name, Expression expr, Location loc,
+                                                    Attributes opt_attrs)
                {
+                       int index;
+                       EnumMember em;
+                       
                        if (defined_names.Contains (name))
                                return AdditionResult.NameExists;
 
-                       DefineName (name, expr);
+                       index = ordered_enums.Add (name);
+                       em = new EnumMember (this, expr, name, loc, opt_attrs, index);
+                       DefineName (name, em);
 
-                       ordered_enums.Add (name);
-                       member_to_location.Add (name, loc);
-                       
                        return AdditionResult.Success;
                }
 
-               //
-               // This is used by corlib compilation: we map from our
-               // type to a type that is consumable by the DefineField
-               //
-               Type MapToInternalType (Type t)
+               public void RemoveEnumMember (string name)
                {
-                       if (t == TypeManager.int32_type)
-                               return typeof (int);
-                       if (t == TypeManager.int64_type)
-                               return typeof (long);
-                       if (t == TypeManager.uint32_type)
-                               return typeof (uint);
-                       if (t == TypeManager.uint64_type)
-                               return typeof (ulong);
-                       if (t == TypeManager.float_type)
-                               return typeof (float);
-                       if (t == TypeManager.double_type)
-                               return typeof (double);
-                       if (t == TypeManager.byte_type)
-                               return typeof (byte);
-                       if (t == TypeManager.sbyte_type)
-                               return typeof (sbyte);
-                       if (t == TypeManager.char_type)
-                               return typeof (char);
-                       if (t == TypeManager.short_type)
-                               return typeof (short);
-                       if (t == TypeManager.ushort_type)
-                               return typeof (ushort);
-
-                       throw new Exception ();
+                       defined_names.Remove (name);
                }
-               
+
                public override TypeBuilder DefineType ()
                {
                        if (TypeBuilder != null)
                                return TypeBuilder;
-                       
-                       TypeAttributes attr = TypeAttributes.Class | TypeAttributes.Sealed;
 
-                       UnderlyingType = TypeManager.LookupType (BaseType);
-                       
+                       emit_context = new EmitContext (Parent, this, Location, null,
+                                                         UnderlyingType, ModFlags, false);
+
+                       TypeAttributes attr = Modifiers.TypeAttr (ModFlags, IsTopLevel);
+
+                       attr |= TypeAttributes.Class | TypeAttributes.Sealed;
+
+                       UnderlyingType = ResolveType (BaseType, false, Location);
+
                        if (UnderlyingType != TypeManager.int32_type &&
                            UnderlyingType != TypeManager.uint32_type &&
                            UnderlyingType != TypeManager.int64_type &&
@@ -122,38 +253,24 @@ namespace Mono.CSharp {
                            UnderlyingType != TypeManager.ushort_type &&
                            UnderlyingType != TypeManager.byte_type  &&
                            UnderlyingType != TypeManager.sbyte_type) {
-                               Report.Error (1008, Location,
+                               Report.Error (30650, Location,
                                              "Type byte, sbyte, short, ushort, int, uint, " +
                                              "long, or ulong expected (got: " +
-                                             TypeManager.CSharpName (UnderlyingType) + ")");
+                                             TypeManager.MonoBASIC_Name (UnderlyingType) + ")");
                                return null;
                        }
 
                        if (IsTopLevel) {
                                ModuleBuilder builder = CodeGen.ModuleBuilder;
 
-                               if ((ModFlags & Modifiers.PUBLIC) != 0)
-                                       attr |= TypeAttributes.Public;
-                               else
-                                       attr |= TypeAttributes.NotPublic;
-                               
                                TypeBuilder = builder.DefineType (Name, attr, TypeManager.enum_type);
                        } else {
                                TypeBuilder builder = Parent.TypeBuilder;
 
-                               if ((ModFlags & Modifiers.PUBLIC) != 0)
-                                       attr |= TypeAttributes.NestedPublic;
-                               else
-                                       attr |= TypeAttributes.NestedPrivate;
-
-                               
                                TypeBuilder = builder.DefineNestedType (
                                        Basename, attr, TypeManager.enum_type);
                        }
 
-                       //
-                       // Call MapToInternalType for corlib
-                       //
                        TypeBuilder.DefineField ("value__", UnderlyingType,
                                                 FieldAttributes.Public | FieldAttributes.SpecialName
                                                 | FieldAttributes.RTSpecialName);
@@ -163,7 +280,7 @@ namespace Mono.CSharp {
                        return TypeBuilder;
                }
 
-               bool IsValidEnumConstant (Expression e)
+               public static bool IsValidEnumConstant (Expression e)
                {
                        if (!(e is Constant))
                                return false;
@@ -176,7 +293,7 @@ namespace Mono.CSharp {
                                return false;
                }
 
-               object GetNextDefaultValue (object default_value)
+               static public object GetNextDefaultValue (object default_value, Type UnderlyingType)
                {
                        if (UnderlyingType == TypeManager.int32_type) {
                                int i = (int) default_value;
@@ -239,16 +356,16 @@ namespace Mono.CSharp {
                        return null;
                }
 
-               void Error_ConstantValueCannotBeConverted (object val, Location loc)
+               public static void Error_ConstantValueCannotBeConverted (object val, Location loc, Type UnderlyingType)
                {
                        if (val is Constant)
-                               Report.Error (31, loc, "Constant value '" + ((Constant) val).AsString () +
+                               Report.Error (30439, loc, "Constant value '" + ((Constant) val).AsString () +
                                              "' cannot be converted" +
-                                             " to a " + TypeManager.CSharpName (UnderlyingType));
+                                             " to a " + TypeManager.MonoBASIC_Name (UnderlyingType));
                        else 
-                               Report.Error (31, loc, "Constant value '" + val +
+                               Report.Error (30439, loc, "Constant value '" + val +
                                              "' cannot be converted" +
-                                             " to a " + TypeManager.CSharpName (UnderlyingType));
+                                             " to a " + TypeManager.MonoBASIC_Name (UnderlyingType));
                        return;
                }
 
@@ -256,184 +373,90 @@ namespace Mono.CSharp {
                ///  This is used to lookup the value of an enum member. If the member is undefined,
                ///  it attempts to define it and return its value
                /// </summary>
-               public object LookupEnumValue (EmitContext ec, string name, Location loc)
+               public object LookupEnumValue (string name)
                {
-                       object default_value = null;
-                       Constant c = null;
+                       EnumMember em;
 
-                       default_value = member_to_value [name];
+                       // first check whether the requested name is there
+                       // in the member list of enum
 
-                       if (default_value != null)
-                               return default_value;
+                       em = this [name];
 
-                       if (!defined_names.Contains (name)) {
-                               Report.Error (117, loc, "'"+ Name + "' does not contain a definition for '"
-                                             + name + "'");
+                       if (em == null)
                                return null;
-                       }
-
-                       //
-                       // So if the above doesn't happen, we have a member that is undefined
-                       // We now proceed to define it 
-                       //
-                       Expression val = this [name];
-
-                       if (val == null) {
-                               
-                               int idx = ordered_enums.IndexOf (name);
-
-                               if (idx == 0)
-                                       default_value = 0;
-                               else {
-                                       for (int i = 0; i < idx; ++i) {
-                                               string n = (string) ordered_enums [i];
-                                               Location m_loc = (Mono.CSharp.Location)
-                                                       member_to_location [n];
-                                               default_value = LookupEnumValue (ec, n, m_loc);
-                                       }
-                                       
-                                       default_value = GetNextDefaultValue (default_value);
-                               }
-                               
-                       } else {
-                               bool old = ec.InEnumContext;
-                               ec.InEnumContext = true;
-                               val = val.Resolve (ec);
-                               ec.InEnumContext = old;
-                               
-                               if (val == null) {
-                                       Report.Error (-12, loc, "Definition is circular.");
-                                       return null;
-                               }
-
-                               if (IsValidEnumConstant (val)) {
-                                       c = (Constant) val;
-                                       default_value = c.GetValue ();
-                                       
-                                       if (default_value == null) {
-                                               Error_ConstantValueCannotBeConverted (c, loc);
-                                               return null;
-                                       }
-                                       
-                               } else {
-                                       Report.Error (
-                                               1008, loc,
-                                               "Type byte, sbyte, short, ushort, int, uint, long, or " +
-                                               "ulong expected (have: " + val + ")");
-                                       return null;
-                               }
-                       }
-
-                       FieldAttributes attr = FieldAttributes.Public | FieldAttributes.Static
-                                       | FieldAttributes.Literal;
                        
-                       FieldBuilder fb = TypeBuilder.DefineField (name, UnderlyingType, attr);
-
-                       try {
-                               default_value = Convert.ChangeType (default_value, UnderlyingType);
-                       } catch {
-                               Error_ConstantValueCannotBeConverted (c, loc);
+                       name = em.Name;
+                       FieldBuilder fb = em.DefineMember ();
+                       
+                       if (fb == null) {
                                return null;
+                       } 
+
+                       if (! field_builders.Contains (fb)) {
+                               field_builders.Add (fb);
                        }
 
-                       fb.SetConstant (default_value);
-                       field_builders.Add (fb);
-                       member_to_value [name] = default_value;
+                       return em.GetValue ();
+               }
 
-                       if (!TypeManager.RegisterFieldValue (fb, default_value))
-                               return null;
-                       
-                       return default_value;
+               public override bool DefineMembers (TypeContainer parent)
+               {
+                       return true;
                }
                
                public override bool Define (TypeContainer parent)
                {
-                       //
-                       // If there was an error during DefineEnum, return
-                       //
                        if (TypeBuilder == null)
                                return false;
-                       
+                       /*
                        EmitContext ec = new EmitContext (parent, this, Location, null,
                                                          UnderlyingType, ModFlags, false);
-                       
-                       object default_value = 0;
-                       
-                       FieldAttributes attr = FieldAttributes.Public | FieldAttributes.Static
-                                            | FieldAttributes.Literal;
-
-                       
+                       */
                        foreach (string name in ordered_enums) {
-                               //
-                               // Have we already been defined, thanks to some cross-referencing ?
-                               // 
-                               if (member_to_value.Contains (name))
-                                       continue;
-                               
-                               Location loc = (Mono.CSharp.Location) member_to_location [name];
-
-                               if (this [name] != null) {
-                                       default_value = LookupEnumValue (ec, name, loc);
+                               EnumMember em = this [name];
+                               FieldBuilder fb = em.DefineMember ();
 
-                                       if (default_value == null)
-                                               return true;
-
-                               } else {
-                                       FieldBuilder fb = TypeBuilder.DefineField (
-                                               name, UnderlyingType, attr);
-                                       
-                                       if (default_value == null) {
-                                          Report.Error (543, loc, "Enumerator value for '" + name + "' is too large to " +
-                                                             "fit in its type");
-                                               return false;
-                                       }
-                                       
-                                       try {
-                                               default_value = Convert.ChangeType (default_value, UnderlyingType);
-                                       } catch {
-                                               Error_ConstantValueCannotBeConverted (default_value, loc);
-                                               return false;
-                                       }
+                               if (fb == null) {
+                                       return false;
+                               } 
 
-                                       fb.SetConstant (default_value);
+                               if (!field_builders.Contains (fb)) {
                                        field_builders.Add (fb);
-                                       member_to_value [name] = default_value;
-                                       
-                                       if (!TypeManager.RegisterFieldValue (fb, default_value))
-                                               return false;
                                }
-
-                               default_value = GetNextDefaultValue (default_value);
                        }
-                       
-                       Attribute.ApplyAttributes (ec, TypeBuilder, this, OptAttributes, Location);
 
+                       if (OptAttributes != null)
+                               OptAttributes.Emit (EmitContext, this);
+                       
                        return true;
                }
                
                //
-               // Hack around System.Reflection as found everywhere else
+               // IMemberFinder
                //
-               public MemberInfo [] FindMembers (MemberTypes mt, BindingFlags bf,
-                                                 MemberFilter filter, object criteria)
+               public override MemberList FindMembers (MemberTypes mt, BindingFlags bf,
+                                                       MemberFilter filter, object criteria)
                {
                        ArrayList members = new ArrayList ();
 
                        if ((mt & MemberTypes.Field) != 0) {
+                               
+                               if (criteria is string){
+                                       LookupEnumValue ((string) criteria);
+                               }
+                               
                                foreach (FieldBuilder fb in field_builders)
                                        if (filter (fb, criteria) == true)
                                                members.Add (fb);
                        }
 
-                       int count = members.Count;
+                       return new MemberList (members);
+               }
 
-                       if (count > 0) {
-                               MemberInfo [] mi = new MemberInfo [count];
-                               members.CopyTo (mi, 0);
-                               return mi;
+               public override MemberCache MemberCache {
+                       get {
+                               return null;
                        }
-
-                       return null;
                }
 
                public ArrayList ValueNames {
@@ -443,9 +466,35 @@ namespace Mono.CSharp {
                }
 
                // indexer
-               public Expression this [string name] {
+               public EnumMember this [string name] {
+                       get {
+                               EnumMember em = (EnumMember) defined_names [name];
+
+                               if (em != null)
+                                       return em;
+
+                               name = name.ToLower();
+                               foreach (string nm in ordered_enums) {
+                                       if (nm.ToLower() == name) {
+                                               em = (EnumMember) defined_names [name];
+                                               break;
+                                       }
+                               }
+
+                               return em;
+                       }
+               }
+
+               public EnumMember this[int mem_index] {
+                       get {
+                               string mem_name = (string) ordered_enums [mem_index];;
+                               return (EnumMember) defined_names[mem_name];
+                       }
+               }
+
+               public EmitContext EmitContext {
                        get {
-                               return (Expression) defined_names [name];
+                               return emit_context;
                        }
                }
        }