2004-08-11 Bernie Solomon <bernard@ugsolutions.com>
[mono.git] / mcs / mbas / enum.cs
index fc2bae1b2976c5178831a6e2288fd05f42eaaa8b..bdfb3a4a507701b8acd6a5a806849875bfc2c2e5 100644 (file)
@@ -3,6 +3,7 @@
 //
 // Author: Miguel de Icaza (miguel@gnu.org)
 //         Ravi Pratap     (ravi@ximian.com)
+//         Anirban Bhattacharjee (banirban@novell.com)
 //
 // Licensed under the terms of the GNU GPL
 //
@@ -14,15 +15,15 @@ using System.Collections;
 using System.Reflection;
 using System.Reflection.Emit;
 
-namespace Mono.CSharp {
+namespace Mono.MonoBASIC {
 
        /// <summary>
        ///   Enumeration container
        /// </summary>
        public class Enum : DeclSpace {
-
                ArrayList ordered_enums;
-               public readonly string BaseType;
+               
+               public Expression BaseType;
                public Attributes  OptAttributes;
                
                public Type UnderlyingType;
@@ -34,6 +35,11 @@ namespace Mono.CSharp {
                // This is for members that have been defined
                //
                Hashtable member_to_value;
+
+               //
+               // This is used to mark members we're currently defining
+               //
+               Hashtable in_transit;
                
                ArrayList field_builders;
                
@@ -44,16 +50,18 @@ namespace Mono.CSharp {
                        Modifiers.INTERNAL |
                        Modifiers.PRIVATE;
 
-               public Enum (TypeContainer parent, string type, int mod_flags, string name, Attributes attrs, Location l)
+               public Enum (TypeContainer parent, Expression type, int mod_flags, string name, Attributes attrs, Location l)
                        : base (parent, name, l)
                {
                        this.BaseType = type;
-                       ModFlags = Modifiers.Check (AllowedModifiers, mod_flags, Modifiers.PUBLIC, l);
+                       ModFlags = Modifiers.Check (AllowedModifiers, mod_flags,
+                                                   IsTopLevel ? Modifiers.INTERNAL : Modifiers.PUBLIC, l);
                        OptAttributes = attrs;
 
                        ordered_enums = new ArrayList ();
                        member_to_location = new Hashtable ();
                        member_to_value = new Hashtable ();
+                       in_transit = new Hashtable ();
                        field_builders = new ArrayList ();
                }
 
@@ -117,9 +125,11 @@ namespace Mono.CSharp {
                        if (TypeBuilder != null)
                                return TypeBuilder;
 
-                       TypeAttributes attr = TypeAttributes.Class | TypeAttributes.Sealed;
+                       TypeAttributes attr = Modifiers.TypeAttr (ModFlags, IsTopLevel);
+
+                       attr |= TypeAttributes.Class | TypeAttributes.Sealed;
 
-                       UnderlyingType = TypeManager.LookupType (BaseType);
+                       UnderlyingType = ResolveType (BaseType, false, Location);
 
                        if (UnderlyingType != TypeManager.int32_type &&
                            UnderlyingType != TypeManager.uint32_type &&
@@ -129,31 +139,20 @@ 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);
                        }
@@ -170,7 +169,7 @@ namespace Mono.CSharp {
                        return TypeBuilder;
                }
 
-               bool IsValidEnumConstant (Expression e)
+           bool IsValidEnumConstant (Expression e)
                {
                        if (!(e is Constant))
                                return false;
@@ -249,16 +248,139 @@ namespace Mono.CSharp {
                void Error_ConstantValueCannotBeConverted (object val, Location loc)
                {
                        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;
                }
 
+               /// <summary>
+               ///  Determines if a standard implicit conversion exists from
+               ///  expr_type to target_type
+               /// </summary>
+               public static bool ImplicitConversionExists (Type expr_type, Type target_type)
+               {
+                       expr_type = TypeManager.TypeToCoreType (expr_type);
+
+                       if (expr_type == TypeManager.void_type)
+                               return false;
+                       
+                       if (expr_type == target_type)
+                               return true;
+
+                       // First numeric conversions 
+
+                       if (expr_type == TypeManager.sbyte_type){
+                               //
+                               // From sbyte to short, int, long, float, double.
+                               //
+                               if ((target_type == TypeManager.int32_type) || 
+                                   (target_type == TypeManager.int64_type) ||
+                                   (target_type == TypeManager.double_type) ||
+                                   (target_type == TypeManager.float_type)  ||
+                                   (target_type == TypeManager.short_type) ||
+                                   (target_type == TypeManager.decimal_type))
+                                       return true;
+                               
+                       } else if (expr_type == TypeManager.byte_type){
+                               //
+                               // From byte to short, ushort, int, uint, long, ulong, float, double
+                               // 
+                               if ((target_type == TypeManager.short_type) ||
+                                   (target_type == TypeManager.ushort_type) ||
+                                   (target_type == TypeManager.int32_type) ||
+                                   (target_type == TypeManager.uint32_type) ||
+                                   (target_type == TypeManager.uint64_type) ||
+                                   (target_type == TypeManager.int64_type) ||
+                                   (target_type == TypeManager.float_type) ||
+                                   (target_type == TypeManager.double_type) ||
+                                   (target_type == TypeManager.decimal_type))
+                                       return true;
+       
+                       } else if (expr_type == TypeManager.short_type){
+                               //
+                               // From short to int, long, float, double
+                               // 
+                               if ((target_type == TypeManager.int32_type) ||
+                                   (target_type == TypeManager.int64_type) ||
+                                   (target_type == TypeManager.double_type) ||
+                                   (target_type == TypeManager.float_type) ||
+                                   (target_type == TypeManager.decimal_type))
+                                       return true;
+                                       
+                       } else if (expr_type == TypeManager.ushort_type){
+                               //
+                               // From ushort to int, uint, long, ulong, float, double
+                               //
+                               if ((target_type == TypeManager.uint32_type) ||
+                                   (target_type == TypeManager.uint64_type) ||
+                                   (target_type == TypeManager.int32_type) ||
+                                   (target_type == TypeManager.int64_type) ||
+                                   (target_type == TypeManager.double_type) ||
+                                   (target_type == TypeManager.float_type) ||
+                                   (target_type == TypeManager.decimal_type))
+                                       return true;
+                                   
+                       } else if (expr_type == TypeManager.int32_type){
+                               //
+                               // From int to long, float, double
+                               //
+                               if ((target_type == TypeManager.int64_type) ||
+                                   (target_type == TypeManager.double_type) ||
+                                   (target_type == TypeManager.float_type) ||
+                                   (target_type == TypeManager.decimal_type))
+                                       return true;
+                                       
+                       } else if (expr_type == TypeManager.uint32_type){
+                               //
+                               // From uint to long, ulong, float, double
+                               //
+                               if ((target_type == TypeManager.int64_type) ||
+                                   (target_type == TypeManager.uint64_type) ||
+                                   (target_type == TypeManager.double_type) ||
+                                   (target_type == TypeManager.float_type) ||
+                                   (target_type == TypeManager.decimal_type))
+                                       return true;
+                                       
+                       } else if ((expr_type == TypeManager.uint64_type) ||
+                                  (expr_type == TypeManager.int64_type)) {
+                               //
+                               // From long/ulong to float, double
+                               //
+                               if ((target_type == TypeManager.double_type) ||
+                                   (target_type == TypeManager.float_type) ||
+                                   (target_type == TypeManager.decimal_type))
+                                       return true;
+                                   
+                       } else if (expr_type == TypeManager.char_type){
+                               //
+                               // From char to ushort, int, uint, long, ulong, float, double
+                               // 
+                               if ((target_type == TypeManager.ushort_type) ||
+                                   (target_type == TypeManager.int32_type) ||
+                                   (target_type == TypeManager.uint32_type) ||
+                                   (target_type == TypeManager.uint64_type) ||
+                                   (target_type == TypeManager.int64_type) ||
+                                   (target_type == TypeManager.float_type) ||
+                                   (target_type == TypeManager.double_type) ||
+                                   (target_type == TypeManager.decimal_type))
+                                       return true;
+
+                       } else if (expr_type == TypeManager.float_type){
+                               //
+                               // float to double
+                               //
+                               if (target_type == TypeManager.double_type)
+                                       return true;
+                       }       
+                       
+                       return false;
+               }
+
                /// <summary>
                ///  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
@@ -267,9 +389,16 @@ namespace Mono.CSharp {
                {
                        object default_value = null;
                        Constant c = null;
+                       TypeContainer parent = ec.TypeContainer;
 
-                       default_value = member_to_value [name];
+                       // first check whether the requested name is there
+                       // in the member list of enum
+                       if (!(ordered_enums.Contains(name)))
+                               Report.Error (30456, loc,
+                                       name + " is not found in member list of enum " + this.Name);
 
+                       default_value = member_to_value [name];
+                       
                        if (default_value != null)
                                return default_value;
 
@@ -280,62 +409,97 @@ namespace Mono.CSharp {
                        if (!defined_names.Contains (name))
                                return null;
 
+                       if (in_transit.Contains (name)) {
+                               Report.Error (110, loc, "The evaluation of the constant value for `" +
+                                             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 = this [name];
+                       int idx = ordered_enums.IndexOf (name);
 
                        if (val == null) {
                                
-                               int idx = ordered_enums.IndexOf (name);
+                               //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)
+                                               Location m_loc = (Mono.MonoBASIC.Location)
                                                        member_to_location [n];
+                                               in_transit.Add (name, true);
                                                default_value = LookupEnumValue (ec, n, m_loc);
+                                               in_transit.Remove (name);
+                                               if (default_value == null)
+                                                       return null;
                                        }
                                        
                                        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;
+                               // check for any cyclic dependency
+                               if (val is Mono.MonoBASIC.SimpleName) {
+                                       int var_idx = ordered_enums.IndexOf (val.ToString());
+
+                                       if (idx <= var_idx)
+                                               Report.Error(30500, loc,
+                                                       "The evaluation of the constant value for `" +
+                                                       Name + "." + name + "' involves a circular definition");
+                                       else
+                                               default_value = member_to_value [val.ToString()];
                                }
+                               else {
+                                       bool old = ec.InEnumContext;
+                                       ec.InEnumContext = true;
+                                       in_transit.Add (name, true);
+                                       val = val.Resolve (ec);
+                                       in_transit.Remove (name);
+                                       ec.InEnumContext = old;
+
+                                       if (val == null)
+                                               return null;
+
+                                       if (!IsValidEnumConstant (val)) {
+                                               Report.Error (
+                                                       30650, loc,
+                                                       "Type byte, sbyte, short, ushort, int, uint, long, or " +
+                                                       "ulong expected (have: " + val + ")");
+                                               return null;
+                                       }
 
-                               if (IsValidEnumConstant (val)) {
                                        c = (Constant) val;
+                               
                                        default_value = c.GetValue ();
+                               }
+
+                               if (default_value == null) {
+                                       Error_ConstantValueCannotBeConverted (c, loc);
+                                       return null;
+                               }
+
+                               if (val is EnumConstant) {
+                                       Type etype = TypeManager.EnumToUnderlying (c.Type);
                                        
-                                       if (default_value == null) {
-                                               Error_ConstantValueCannotBeConverted (c, loc);
+                                       if ( (!ImplicitConversionExists (etype, UnderlyingType)) &&
+                                               (!Expression.RuntimeConversionExists (ec, val, UnderlyingType)) ){
+                                               Expression.Error_CannotConvertImplicit (
+                                                       loc, c.Type, UnderlyingType);
                                                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);
+                       FieldBuilder fb = TypeBuilder.DefineField (name, TypeBuilder, attr);
 
                        try {
                                default_value = TypeManager.ChangeType (default_value, UnderlyingType);
@@ -358,6 +522,11 @@ namespace Mono.CSharp {
                        
                        return default_value;
                }
+
+               public override bool DefineMembers (TypeContainer parent)
+               {
+                       return true;
+               }
                
                public override bool Define (TypeContainer parent)
                {
@@ -372,38 +541,32 @@ namespace Mono.CSharp {
                        
                        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];
+                               Location loc = (Mono.MonoBASIC.Location) member_to_location [name];
 
                                if (this [name] != null) {
                                        default_value = LookupEnumValue (ec, name, loc);
 
                                        if (default_value == null)
                                                return true;
-
                                } else {
-                                       FieldBuilder fb = TypeBuilder.DefineField (
-                                               name, UnderlyingType, attr);
-                                       
+                                       FieldAttributes attr = FieldAttributes.Public | FieldAttributes.Static
+                                               | FieldAttributes.Literal;
+                       
+                                       FieldBuilder fb = TypeBuilder.DefineField (name, TypeBuilder, attr);
+
                                        if (default_value == null) {
-                                          Report.Error (543, loc, "Enumerator value for '" + name + "' is too large to " +
-                                                             "fit in its type");
+                                               Report.Error (30439, loc, "Enumerator value for '" + name + "' is too large to " +
+                                                       "fit in its type");
                                                return false;
                                        }
-                                       
-                                       try {
+
+                                       try     {
                                                default_value = TypeManager.ChangeType (default_value, UnderlyingType);
-                                       } catch {
+                                       } catch {
                                                Error_ConstantValueCannotBeConverted (default_value, loc);
                                                return false;
                                        }
@@ -411,29 +574,28 @@ namespace Mono.CSharp {
                                        fb.SetConstant (default_value);
                                        field_builders.Add (fb);
                                        member_to_value [name] = default_value;
-                                       
+
                                        if (!TypeManager.RegisterFieldValue (fb, default_value))
                                                return false;
 
                                        //
-                                       // Apply attributes on the enum member
+                                       // Now apply attributes
                                        //
-                                       Attribute.ApplyAttributes (ec, fb, fb, (Attributes) member_to_attributes [name], loc);
+                                       Attribute.ApplyAttributes (ec, fb, fb, (Attributes) member_to_attributes [name], loc); 
                                }
 
                                default_value = GetNextDefaultValue (default_value);
                        }
                        
                        Attribute.ApplyAttributes (ec, TypeBuilder, this, OptAttributes, Location);
-
                        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 ();
 
@@ -443,15 +605,13 @@ namespace Mono.CSharp {
                                                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 {