* TypeDescriptor.cs: fixed properties order in returning collections in PropertyDescr...
[mono.git] / mcs / mcs / enum.cs
1 //
2 // enum.cs: Enum handling.
3 //
4 // Author: Miguel de Icaza (miguel@gnu.org)
5 //         Ravi Pratap     (ravi@ximian.com)
6 //         Marek Safar     (marek.safar@seznam.cz)
7 //
8 // Licensed under the terms of the GNU GPL
9 //
10 // (C) 2001 Ximian, Inc (http://www.ximian.com)
11 //
12
13 using System;
14 using System.Collections;
15 using System.Collections.Specialized;
16 using System.Reflection;
17 using System.Reflection.Emit;
18 using System.Globalization;
19
20 namespace Mono.CSharp {
21
22         public class EnumMember : Const {
23                 protected readonly Enum ParentEnum;
24                 protected readonly Expression ValueExpr;
25                 readonly EnumMember prev_member;
26
27                 public EnumMember (Enum parent, EnumMember prev_member, string name, Expression expr,
28                                    Attributes attrs, Location loc)
29                         : base (parent, new EnumTypeExpr (parent), name, expr, Modifiers.PUBLIC,
30                                 attrs, loc)
31                 {
32                         this.ParentEnum = parent;
33                         this.ValueExpr = expr;
34                         this.prev_member = prev_member;
35                 }
36
37                 protected class EnumTypeExpr : TypeExpr
38                 {
39                         public readonly Enum Enum;
40
41                         public EnumTypeExpr (Enum e)
42                         {
43                                 this.Enum = e;
44                         }
45
46                         protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
47                         {
48                                 type = Enum.CurrentType != null ? Enum.CurrentType : Enum.TypeBuilder;
49                                 return this;
50                         }
51
52                         public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
53                         {
54                                 return DoResolveAsTypeStep (ec);
55                         }
56
57                         public override string Name {
58                                 get { return Enum.Name; }
59                         }
60
61                         public override string FullName {
62                                 get { return Enum.Name; }
63                         }
64                 }
65
66                 static bool IsValidEnumType (Type t)
67                 {
68                         return (t == TypeManager.int32_type || t == TypeManager.uint32_type || t == TypeManager.int64_type ||
69                                 t == TypeManager.byte_type || t == TypeManager.sbyte_type || t == TypeManager.short_type ||
70                                 t == TypeManager.ushort_type || t == TypeManager.uint64_type || t == TypeManager.char_type ||
71                                 t.IsEnum);
72                 }
73
74                 public object Value {
75                         get { return value.GetValue (); }
76                 }
77
78                 public override bool Define ()
79                 {
80                         const FieldAttributes attr = FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.Literal;
81                         FieldBuilder = Parent.TypeBuilder.DefineField (Name, MemberType, attr);
82                         Parent.MemberCache.AddMember (FieldBuilder, this);
83                         TypeManager.RegisterConstant (FieldBuilder, this);
84                         return true;
85                 }
86         
87                 protected override Constant DoResolveValue (EmitContext ec)
88                 {
89                         if (ValueExpr != null) {
90                                 Constant c = ValueExpr.ResolveAsConstant (ec, this);
91                                 if (c == null)
92                                         return null;
93
94                                 if (c is EnumConstant)
95                                         c = ((EnumConstant)c).Child;
96
97                                 c = c.ImplicitConversionRequired (ParentEnum.UnderlyingType, Location);
98                                 if (c == null)
99                                         return null;
100
101                                 if (!IsValidEnumType (c.Type)) {
102                                         Enum.Error_1008 (Location);
103                                         return null;
104                                 }
105
106                                 return new EnumConstant (c, MemberType);
107                         }
108
109                         if (prev_member == null) {
110                                 return new EnumConstant (
111                                         New.Constantify (ParentEnum.UnderlyingType), MemberType);
112                         }
113
114                         if (!prev_member.ResolveValue ()) {
115                                 prev_member.value = new EnumConstant (
116                                         New.Constantify (ParentEnum.UnderlyingType), MemberType);
117                                 return null;
118                         }
119
120                         try {
121                                 return (EnumConstant) prev_member.value.Increment ();
122                         } catch (OverflowException) {
123                                 Report.Error (543, Location, "The enumerator value `{0}' is too " +
124                                               "large to fit in its type `{1}'", GetSignatureForError (),
125                                               TypeManager.CSharpName (ParentEnum.UnderlyingType));
126                                 return null;
127                         }
128                 }
129         }
130
131         /// <summary>
132         ///   Enumeration container
133         /// </summary>
134         public class Enum : TypeContainer
135         {
136                 Expression base_type;
137
138                 public Type UnderlyingType;
139
140                 public const int AllowedModifiers =
141                         Modifiers.NEW |
142                         Modifiers.PUBLIC |
143                         Modifiers.PROTECTED |
144                         Modifiers.INTERNAL |
145                         Modifiers.PRIVATE;
146
147                 public Enum (NamespaceEntry ns, DeclSpace parent, Expression type,
148                              int mod_flags, MemberName name, Attributes attrs)
149                         : base (ns, parent, name, attrs, Kind.Enum)
150                 {
151                         this.base_type = type;
152                         int accmods = IsTopLevel ? Modifiers.INTERNAL : Modifiers.PRIVATE;
153                         ModFlags = Modifiers.Check (AllowedModifiers, mod_flags, accmods, Location);
154                 }
155
156                 public void AddEnumMember (EnumMember em)
157                 {
158                         if (em.Name == "value__") {
159                                 Report.Error (76, em.Location, "An item in an enumeration cannot " +
160                                               "have an identifier `value__'");
161                                 return;
162                         }
163
164                         AddConstant (em);
165                 }
166
167                 public static void Error_1008 (Location loc)
168                 {
169                         Report.Error (1008, loc, "Type byte, sbyte, short, ushort, " +
170                                       "int, uint, long or ulong expected");
171                 }
172
173                 protected override bool DefineNestedTypes ()
174                 {
175                         if (!base.DefineNestedTypes ())
176                                 return false;
177
178                         if (!(base_type is TypeLookupExpression)) {
179                                 Error_1008 (Location);
180                                 return false;
181                         }
182
183                         TypeExpr ute = base_type.ResolveAsTypeTerminal (this, false);
184                         UnderlyingType = ute.Type;
185
186                         if (UnderlyingType != TypeManager.int32_type &&
187                             UnderlyingType != TypeManager.uint32_type &&
188                             UnderlyingType != TypeManager.int64_type &&
189                             UnderlyingType != TypeManager.uint64_type &&
190                             UnderlyingType != TypeManager.short_type &&
191                             UnderlyingType != TypeManager.ushort_type &&
192                             UnderlyingType != TypeManager.byte_type  &&
193                             UnderlyingType != TypeManager.sbyte_type) {
194                                 Error_1008 (Location);
195                                 return false;
196                         }
197
198                         //
199                         // Call MapToInternalType for corlib
200                         //
201                         TypeBuilder.DefineField ("value__", UnderlyingType,
202                                                  FieldAttributes.Public | FieldAttributes.SpecialName
203                                                  | FieldAttributes.RTSpecialName);
204
205                         return true;
206                 }
207
208                 protected override bool DoDefineMembers ()
209                 {
210                         member_cache = new MemberCache (TypeManager.enum_type, this);
211                         DefineContainerMembers (constants);
212                         return true;
213                 }
214
215                 //
216                 // Used for error reporting only
217                 //
218                 public EnumMember GetDefinition (object value)
219                 {
220                         foreach (EnumMember e in defined_names.Values) {
221                                 if (e.Value.Equals (value))
222                                         return e;
223                         }
224
225                         throw new ArgumentOutOfRangeException (value.ToString ());
226                 }
227
228                 protected override bool VerifyClsCompliance ()
229                 {
230                         if (!base.VerifyClsCompliance ())
231                                 return false;
232
233                         if (UnderlyingType == TypeManager.uint32_type ||
234                                 UnderlyingType == TypeManager.uint64_type ||
235                                 UnderlyingType == TypeManager.ushort_type) {
236                                 Report.Error (3009, Location, "`{0}': base type `{1}' is not CLS-compliant", GetSignatureForError (), TypeManager.CSharpName (UnderlyingType));
237                         }
238
239                         return true;
240                 }       
241
242                 public override AttributeTargets AttributeTargets {
243                         get {
244                                 return AttributeTargets.Enum;
245                         }
246                 }
247
248                 protected override TypeAttributes TypeAttr {
249                         get {
250                                 return Modifiers.TypeAttr (ModFlags, IsTopLevel) |
251                                         TypeAttributes.Class | TypeAttributes.Sealed | base.TypeAttr;
252                         }
253                 }
254         }
255 }