Wed Feb 24 15:47:16 CET 2010 Paolo Molaro <lupus@ximian.com>
[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 // Dual licensed under the terms of the MIT X11 or GNU GPL
9 //
10 // Copyright 2001 Ximian, Inc (http://www.ximian.com)
11 // Copyright 2003-2003 Novell, Inc (http://www.novell.com)
12 //
13
14 using System;
15 using System.Collections.Generic;
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         {
24                 class EnumTypeExpr : TypeExpr
25                 {
26                         public readonly Enum Enum;
27
28                         public EnumTypeExpr (Enum e)
29                         {
30                                 this.Enum = e;
31                         }
32
33                         protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
34                         {
35                                 type = Enum.CurrentType != null ? Enum.CurrentType : Enum.TypeBuilder;
36                                 return this;
37                         }
38
39                         public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
40                         {
41                                 return DoResolveAsTypeStep (ec);
42                         }
43                 }
44
45                 public EnumMember (Enum parent, EnumMember prev_member, string name, Expression expr,
46                                    Attributes attrs, Location loc)
47                         : base (parent, new EnumTypeExpr (parent), name, null, Modifiers.PUBLIC,
48                                 attrs, loc)
49                 {
50                         initializer = new EnumInitializer (this, expr, prev_member);
51                 }
52
53                 static bool IsValidEnumType (Type t)
54                 {
55                         return (t == TypeManager.int32_type || t == TypeManager.uint32_type || t == TypeManager.int64_type ||
56                                 t == TypeManager.byte_type || t == TypeManager.sbyte_type || t == TypeManager.short_type ||
57                                 t == TypeManager.ushort_type || t == TypeManager.uint64_type || t == TypeManager.char_type ||
58                                 TypeManager.IsEnumType (t));
59                 }
60
61                 public override Constant ConvertInitializer (ResolveContext rc, Constant expr)
62                 {
63                         if (expr is EnumConstant)
64                                 expr = ((EnumConstant) expr).Child;
65
66                         var underlying = ((Enum) Parent).UnderlyingType;
67                         if (expr != null) {
68                                 expr = expr.ImplicitConversionRequired (rc, underlying, Location);
69                                 if (expr != null && !IsValidEnumType (expr.Type)) {
70                                         Enum.Error_1008 (Location, Report);
71                                         expr = null;
72                                 }
73                         }
74
75                         if (expr == null)
76                                 expr = New.Constantify (underlying);
77
78                         return new EnumConstant (expr, MemberType).Resolve (rc);
79                 }
80
81                 public override bool Define ()
82                 {
83                         if (!ResolveMemberType ())
84                                 return false;
85
86                         const FieldAttributes attr = FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.Literal;
87                         FieldBuilder = Parent.TypeBuilder.DefineField (Name, MemberType, attr);
88                         spec = new ConstSpec (this, FieldBuilder, ModFlags, initializer);
89
90                         Parent.MemberCache.AddMember (FieldBuilder, spec);
91                         TypeManager.RegisterConstant (FieldBuilder, (ConstSpec) spec);
92
93                         return true;
94                 }
95         }
96
97         class EnumInitializer : ConstInitializer
98         {
99                 EnumMember prev;
100
101                 public EnumInitializer (Const field, Expression init, EnumMember prev)
102                         : base (field, init)
103                 {
104                         this.prev = prev;
105                 }
106
107                 protected override Expression DoResolveInitializer (ResolveContext rc)
108                 {
109                         if (expr != null)
110                                 return base.DoResolveInitializer (rc);
111
112                         if (prev == null)
113                                 return field.ConvertInitializer (rc, null);
114
115                         try {
116                                 var ec = prev.Initializer.Resolve (rc) as EnumConstant;
117                                 expr = ec.Increment ().Resolve (rc);
118                         } catch (OverflowException) {
119                                 rc.Report.Error (543, field.Location,
120                                         "The enumerator value `{0}' is outside the range of enumerator underlying type `{1}'",
121                                         field.GetSignatureForError (),
122                                         TypeManager.CSharpName (((Enum) field.Parent).UnderlyingType));
123
124                                 expr = field.ConvertInitializer (rc, null);
125                         }               
126
127                         return expr;
128                 }
129         }
130
131         /// <summary>
132         ///   Enumeration container
133         /// </summary>
134         public class Enum : TypeContainer
135         {
136                 public static readonly string UnderlyingValueField = "value__";
137
138                 TypeExpr base_type;
139
140                 const Modifiers AllowedModifiers =
141                         Modifiers.NEW |
142                         Modifiers.PUBLIC |
143                         Modifiers.PROTECTED |
144                         Modifiers.INTERNAL |
145                         Modifiers.PRIVATE;
146
147                 public Enum (NamespaceEntry ns, DeclSpace parent, TypeExpr type,
148                              Modifiers mod_flags, MemberName name, Attributes attrs)
149                         : base (ns, parent, name, attrs, MemberKind.Enum)
150                 {
151                         this.base_type = type;
152                         var accmods = IsTopLevel ? Modifiers.INTERNAL : Modifiers.PRIVATE;
153                         ModFlags = ModifiersExtensions.Check (AllowedModifiers, mod_flags, accmods, Location, Report);
154                 }
155
156                 public void AddEnumMember (EnumMember em)
157                 {
158                         if (em.Name == UnderlyingValueField) {
159                                 Report.Error (76, em.Location, "An item in an enumeration cannot have an identifier `{0}'",
160                                         UnderlyingValueField);
161                                 return;
162                         }
163
164                         AddConstant (em);
165                 }
166
167                 public static void Error_1008 (Location loc, Report Report)
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                         //
179                         // Call MapToInternalType for corlib
180                         //
181                         TypeBuilder.DefineField (UnderlyingValueField, UnderlyingType,
182                                                  FieldAttributes.Public | FieldAttributes.SpecialName
183                                                  | FieldAttributes.RTSpecialName);
184
185                         return true;
186                 }
187
188                 protected override bool DoDefineMembers ()
189                 {
190                         member_cache = new MemberCache (TypeManager.enum_type, this);
191                         DefineContainerMembers (constants);
192                         return true;
193                 }
194
195                 public override bool IsUnmanagedType ()
196                 {
197                         return true;
198                 }
199
200                 public Type UnderlyingType {
201                         get {
202                                 return base_type.Type;
203                         }
204                 }
205
206                 protected override bool VerifyClsCompliance ()
207                 {
208                         if (!base.VerifyClsCompliance ())
209                                 return false;
210
211                         if (UnderlyingType == TypeManager.uint32_type ||
212                                 UnderlyingType == TypeManager.uint64_type ||
213                                 UnderlyingType == TypeManager.ushort_type) {
214                                 Report.Warning (3009, 1, Location, "`{0}': base type `{1}' is not CLS-compliant", GetSignatureForError (), TypeManager.CSharpName (UnderlyingType));
215                         }
216
217                         return true;
218                 }       
219
220                 public override AttributeTargets AttributeTargets {
221                         get {
222                                 return AttributeTargets.Enum;
223                         }
224                 }
225
226                 protected override TypeAttributes TypeAttr {
227                         get {
228                                 return ModifiersExtensions.TypeAttr (ModFlags, IsTopLevel) |
229                                         TypeAttributes.Class | TypeAttributes.Sealed | base.TypeAttr;
230                         }
231                 }
232         }
233
234         public class EnumSpec : TypeSpec
235         {
236                 public EnumSpec (MemberKind kind, ITypeDefinition definition, TypeSpec underlyingType, Type info, string name, Modifiers modifiers)
237                         : base (kind, definition, info, name, modifiers)
238                 {
239                         this.UnderlyingType = underlyingType;
240                 }
241
242                 public TypeSpec UnderlyingType { get; private set; }
243         }
244 }