* cs-parser.jay (GetTokenName): Mark GENERATE_COMPLETION and COMPLETE_COMPLETION...
[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;
16 using System.Collections.Specialized;
17 using System.Reflection;
18 using System.Reflection.Emit;
19 using System.Globalization;
20
21 namespace Mono.CSharp {
22
23         public class EnumMember : Const {
24                 protected readonly Enum ParentEnum;
25                 protected readonly Expression ValueExpr;
26                 readonly EnumMember prev_member;
27
28                 public EnumMember (Enum parent, EnumMember prev_member, string name, Expression expr,
29                                    Attributes attrs, Location loc)
30                         : base (parent, new EnumTypeExpr (parent), name, expr, Modifiers.PUBLIC,
31                                 attrs, loc)
32                 {
33                         this.ParentEnum = parent;
34                         this.ValueExpr = expr;
35                         this.prev_member = prev_member;
36                 }
37
38                 protected class EnumTypeExpr : TypeExpr
39                 {
40                         public readonly Enum Enum;
41
42                         public EnumTypeExpr (Enum e)
43                         {
44                                 this.Enum = e;
45                         }
46
47                         protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
48                         {
49                                 type = Enum.CurrentType != null ? Enum.CurrentType : Enum.TypeBuilder;
50                                 return this;
51                         }
52
53                         public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
54                         {
55                                 return DoResolveAsTypeStep (ec);
56                         }
57                 }
58
59                 static bool IsValidEnumType (Type t)
60                 {
61                         return (t == TypeManager.int32_type || t == TypeManager.uint32_type || t == TypeManager.int64_type ||
62                                 t == TypeManager.byte_type || t == TypeManager.sbyte_type || t == TypeManager.short_type ||
63                                 t == TypeManager.ushort_type || t == TypeManager.uint64_type || t == TypeManager.char_type ||
64                                 TypeManager.IsEnumType (t));
65                 }
66
67                 public object Value {
68                         get { return ResolveValue () ? value.GetValue () : null; }
69                 }
70
71                 public override bool Define ()
72                 {
73                         if (!ResolveMemberType ())
74                                 return false;
75
76                         const FieldAttributes attr = FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.Literal;
77                         FieldBuilder = Parent.TypeBuilder.DefineField (Name, MemberType, attr);
78                         Parent.MemberCache.AddMember (FieldBuilder, this);
79                         TypeManager.RegisterConstant (FieldBuilder, this);
80                         return true;
81                 }
82         
83                 protected override Constant DoResolveValue (EmitContext ec)
84                 {
85                         if (ValueExpr != null) {
86                                 Constant c = ValueExpr.ResolveAsConstant (ec, this);
87                                 if (c == null)
88                                         return null;
89
90                                 if (c is EnumConstant)
91                                         c = ((EnumConstant)c).Child;
92
93                                 c = c.ImplicitConversionRequired (ec, ParentEnum.UnderlyingType, Location);
94                                 if (c == null)
95                                         return null;
96
97                                 if (!IsValidEnumType (c.Type)) {
98                                         Enum.Error_1008 (Location);
99                                         return null;
100                                 }
101
102                                 return new EnumConstant (c, MemberType);
103                         }
104
105                         if (prev_member == null)
106                                 return new EnumConstant (
107                                         New.Constantify (ParentEnum.UnderlyingType), MemberType);
108
109                         if (!prev_member.ResolveValue ())
110                                 return null;
111
112                         try {
113                                 return (EnumConstant) prev_member.value.Increment ();
114                         } catch (OverflowException) {
115                                 Report.Error (543, Location, "The enumerator value `{0}' is too " +
116                                               "large to fit in its type `{1}'", GetSignatureForError (),
117                                               TypeManager.CSharpName (ParentEnum.UnderlyingType));
118                                 return null;
119                         }
120                 }
121         }
122
123         /// <summary>
124         ///   Enumeration container
125         /// </summary>
126         public class Enum : TypeContainer
127         {
128                 public static readonly string UnderlyingValueField = "value__";
129
130                 TypeExpr base_type;
131
132                 const int AllowedModifiers =
133                         Modifiers.NEW |
134                         Modifiers.PUBLIC |
135                         Modifiers.PROTECTED |
136                         Modifiers.INTERNAL |
137                         Modifiers.PRIVATE;
138
139                 public Enum (NamespaceEntry ns, DeclSpace parent, TypeExpr type,
140                              int mod_flags, MemberName name, Attributes attrs)
141                         : base (ns, parent, name, attrs, Kind.Enum)
142                 {
143                         this.base_type = type;
144                         int accmods = IsTopLevel ? Modifiers.INTERNAL : Modifiers.PRIVATE;
145                         ModFlags = Modifiers.Check (AllowedModifiers, mod_flags, accmods, Location);
146                 }
147
148                 public void AddEnumMember (EnumMember em)
149                 {
150                         if (em.Name == UnderlyingValueField) {
151                                 Report.Error (76, em.Location, "An item in an enumeration cannot have an identifier `{0}'",
152                                         UnderlyingValueField);
153                                 return;
154                         }
155
156                         AddConstant (em);
157                 }
158
159                 public static void Error_1008 (Location loc)
160                 {
161                         Report.Error (1008, loc, "Type byte, sbyte, short, ushort, " +
162                                       "int, uint, long or ulong expected");
163                 }
164
165                 protected override bool DefineNestedTypes ()
166                 {
167                         if (!base.DefineNestedTypes ())
168                                 return false;
169
170                         //
171                         // Call MapToInternalType for corlib
172                         //
173                         TypeBuilder.DefineField (UnderlyingValueField, UnderlyingType,
174                                                  FieldAttributes.Public | FieldAttributes.SpecialName
175                                                  | FieldAttributes.RTSpecialName);
176
177                         return true;
178                 }
179
180                 public override bool Define ()
181                 {
182                         member_cache = new MemberCache (TypeManager.enum_type, this);
183                         DefineContainerMembers (constants);
184                         return true;
185                 }
186
187                 public override bool IsUnmanagedType ()
188                 {
189                         return true;
190                 }
191
192                 public Type UnderlyingType {
193                         get {
194                                 return base_type.Type;
195                         }
196                 }
197
198                 protected override bool VerifyClsCompliance ()
199                 {
200                         if (!base.VerifyClsCompliance ())
201                                 return false;
202
203                         if (UnderlyingType == TypeManager.uint32_type ||
204                                 UnderlyingType == TypeManager.uint64_type ||
205                                 UnderlyingType == TypeManager.ushort_type) {
206                                 Report.Warning (3009, 1, Location, "`{0}': base type `{1}' is not CLS-compliant", GetSignatureForError (), TypeManager.CSharpName (UnderlyingType));
207                         }
208
209                         return true;
210                 }       
211
212                 public override AttributeTargets AttributeTargets {
213                         get {
214                                 return AttributeTargets.Enum;
215                         }
216                 }
217
218                 protected override TypeAttributes TypeAttr {
219                         get {
220                                 return Modifiers.TypeAttr (ModFlags, IsTopLevel) |
221                                         TypeAttributes.Class | TypeAttributes.Sealed | base.TypeAttr;
222                         }
223                 }
224         }
225 }