2 // const.cs: Constant declarations.
5 // Miguel de Icaza (miguel@ximian.com)
7 // (C) 2001 Ximian, Inc.
12 // This is needed because the following situation arises:
14 // The FieldBuilder is declared with the real type for an enumeration
16 // When we attempt to set the value for the constant, the FieldBuilder.SetConstant
17 // function aborts because it requires its argument to be of the same type
22 namespace Mono.MonoBASIC {
26 using System.Reflection;
27 using System.Reflection.Emit;
28 using System.Collections;
30 public class Const : MemberCore {
31 public Expression ConstantType;
32 public Expression Expr;
33 public FieldBuilder FieldBuilder;
36 bool resolved = false;
37 object ConstantValue = null;
40 bool in_transit = false;
42 public const int AllowedModifiers =
49 public Const (Expression constant_type, string name, Expression expr, int mod_flags,
50 Attributes attrs, Location loc)
51 : base (name, attrs, loc)
53 ConstantType = constant_type;
56 ModFlags = Modifiers.Check (AllowedModifiers, mod_flags, Modifiers.PRIVATE, loc);
59 public override AttributeTargets AttributeTargets {
61 return AttributeTargets.Field;
65 public FieldAttributes FieldAttr {
67 return FieldAttributes.Literal | FieldAttributes.Static |
68 Modifiers.FieldAttr (ModFlags) ;
73 void dump_tree (Type t)
75 Console.WriteLine ("Dumping hierarchy");
77 Console.WriteLine (" " + t.FullName + " " +
78 (t.GetType ().IsEnum ? "yes" : "no"));
85 /// Defines the constant in the @parent
87 public override bool Define (TypeContainer parent)
89 type = parent.ResolveType (ConstantType, false, Location);
94 if (!TypeManager.IsBuiltinType (type) &&
95 (!type.IsSubclassOf (TypeManager.enum_type))) {
98 "Constant type is not valid (only system types are allowed)");
102 // if no type is declared expicitely
103 // set the expression type as the type of constant
104 if (type == TypeManager.object_type){
105 if (Expr is IntLiteral)
106 type = TypeManager.int32_type;
107 else if (Expr is UIntLiteral)
108 type = TypeManager.uint32_type;
109 else if (Expr is LongLiteral)
110 type = TypeManager.int64_type;
111 else if (Expr is ULongLiteral)
112 type = TypeManager.uint64_type;
113 else if (Expr is FloatLiteral)
114 type = TypeManager.float_type;
115 else if (Expr is DoubleLiteral)
116 type = TypeManager.double_type;
117 else if (Expr is StringLiteral)
118 type = TypeManager.string_type;
119 else if (Expr is ShortLiteral)
120 type = TypeManager.short_type;
121 else if (Expr is UShortConstant)
122 type = TypeManager.ushort_type;
123 else if (Expr is SByteConstant)
124 type = TypeManager.sbyte_type;
125 else if (Expr is ByteConstant)
126 type = TypeManager.byte_type;
127 else if (Expr is CharConstant)
128 type = TypeManager.char_type;
129 else if (Expr is BoolConstant)
130 type = TypeManager.bool_type;
131 else if (Expr is DateConstant)
132 type = TypeManager.date_type;
134 Type ptype = parent.TypeBuilder.BaseType;
137 MemberList list = TypeContainer.FindMembers (
138 ptype, MemberTypes.Field, BindingFlags.Public,
139 Type.FilterName, Name);
141 if ((list.Count > 0) && ((ModFlags & Modifiers.SHADOWS) == 0))
144 "Const '" + Name + "' should be declared " +
145 "Shadows since the base type '" + ptype.Name +
146 "' has a Const with same name");
147 if (list.Count == 0) {
148 // if a member of module is not inherited from Object class
149 // can not be declared protected
150 if ((parent is Module) && ((ModFlags & Modifiers.PROTECTED) != 0))
151 Report.Error (30593, Location,
152 "'Const' inside a 'Module' can not be " +
153 "declared as 'Protected'");
155 /*if ((ModFlags & Modifiers.NEW) != 0)
156 WarningNotHiding (parent);*/
159 /*else if ((ModFlags & Modifiers.NEW) != 0)
160 WarningNotHiding (parent);*/
162 if ((parent is Struct) && ((ModFlags & Modifiers.PROTECTED) != 0))
163 Report.Error (30435, Location,
164 "'Const' inside a 'Structure' can not be " +
165 "declared as 'Protected'");
167 FieldBuilder = parent.TypeBuilder.DefineField (Name, type, FieldAttr);
169 TypeManager.RegisterConstant (FieldBuilder, this);
175 // Changes the type of the constant expression `expr' to the Type `type'
176 // Returns null on failure.
178 public static Constant ChangeType (Location loc, Constant expr, Type type, EmitContext ec)
180 if (type == TypeManager.object_type)
185 // from the null type to any reference-type.
186 if (expr.Type == TypeManager.null_type && !type.IsValueType && !TypeManager.IsEnumType (type))
187 return NullLiteral.Null;
189 if (!Expression.ImplicitConversionExists (ec, expr, type)){
190 Expression.Error_CannotConvertImplicit (loc, expr.Type, type);
194 // Special-case: The 0 literal can be converted to an enum value,
195 // and ImplicitStandardConversionExists will return true in that case.
196 if (expr.Type == TypeManager.int32_type && TypeManager.IsEnumType (type)){
197 if (expr is IntLiteral && ((IntLiteral) expr).Value == 0)
198 return new EnumConstant (expr, type);
201 object constant_value = TypeManager.ChangeType1 (expr.GetValue (), type, out fail);
203 // Error_CannotImplicitConversion (loc, expr.Type, type);
206 // We should always catch the error before this is ever
207 // reached, by calling Convert.ImplicitStandardConversionExists
209 throw new Exception (
210 String.Format ("LookupConstantValue: This should never be reached {0} {1}", expr.Type, type));
214 if (type == TypeManager.int32_type)
215 retval = new IntConstant ((int) constant_value);
216 else if (type == TypeManager.uint32_type)
217 retval = new UIntConstant ((uint) constant_value);
218 else if (type == TypeManager.int64_type)
219 retval = new LongConstant ((long) constant_value);
220 else if (type == TypeManager.uint64_type)
221 retval = new ULongConstant ((ulong) constant_value);
222 else if (type == TypeManager.float_type)
223 retval = new FloatConstant ((float) constant_value);
224 else if (type == TypeManager.double_type)
225 retval = new DoubleConstant ((double) constant_value);
226 else if (type == TypeManager.string_type)
227 retval = new StringConstant ((string) constant_value);
228 else if (type == TypeManager.short_type)
229 retval = new ShortConstant ((short) constant_value);
230 else if (type == TypeManager.ushort_type)
231 retval = new UShortConstant ((ushort) constant_value);
232 else if (type == TypeManager.sbyte_type)
233 retval = new SByteConstant ((sbyte) constant_value);
234 else if (type == TypeManager.byte_type)
235 retval = new ByteConstant ((byte) constant_value);
236 else if (type == TypeManager.char_type)
237 retval = new CharConstant ((char) constant_value);
238 else if (type == TypeManager.bool_type)
239 retval = new BoolConstant ((bool) constant_value);
240 else if (type == TypeManager.decimal_type)
241 retval = new DecimalConstant ((decimal) constant_value);
243 throw new Exception ("LookupConstantValue: Unhandled constant type: " + type);
249 /// Looks up the value of a constant field. Defines it if it hasn't
250 /// already been. Similar to LookupEnumValue in spirit.
252 public bool LookupConstantValue (out object value, EmitContext ec)
255 value = ConstantValue;
260 Report.Error (110, Location,
261 "The evaluation of the constant value for `" +
262 Name + "' involves a circular definition.");
268 int errors = Report.Errors;
271 // We might have cleared Expr ourselves in a recursive definition
278 Expr = Expr.Resolve (ec);
283 if (errors == Report.Errors)
284 Report.Error (150, Location, "A constant value is expected");
289 Expression real_expr = Expr;
291 Constant ce = Expr as Constant;
293 UnCheckedExpr un_expr = Expr as UnCheckedExpr;
294 CheckedExpr ch_expr = Expr as CheckedExpr;
295 EmptyCast ec_expr = Expr as EmptyCast;
296 if ((un_expr != null) && (un_expr.Expr is Constant))
298 else if ((ch_expr != null) && (ch_expr.Expr is Constant))
300 //else if ((ec_expr != null) && (ec_expr.Child is Constant))
301 // Expr = ec_expr.Child;
302 else if (Expr is ArrayCreation){
303 Report.Error (133, Location, "Arrays can not be constant");
305 if (errors == Report.Errors)
306 Report.Error (150, Location, "A constant value is expected");
311 ce = Expr as Constant;
314 // if (MemberType != real_expr.Type) {
315 if (type != Expr.Type) {
317 ce = ChangeType (Location, ce, type, ec);
326 ConstantValue = ce.GetValue ();
330 // This sadly does not work for our user-defined enumerations types ;-(
333 ConstantValue = System.Enum.ToObject (
334 type, ConstantValue);
335 } catch (ArgumentException){
338 ".NET SDK 1.0 does not permit to create the constant "+
339 " field from a user-defined enumeration");
343 if (ce is DecimalConstant) {
344 Decimal d = ((DecimalConstant)ce).Value;
345 int[] bits = Decimal.GetBits (d);
346 object[] args = new object[] { (byte)(bits [3] >> 16), (byte)(bits [3] >> 31), (uint)bits [2], (uint)bits [1], (uint)bits [0] };
347 CustomAttributeBuilder cab = new CustomAttributeBuilder (TypeManager.decimal_constant_attribute_ctor, args);
348 FieldBuilder.SetCustomAttribute (cab);
351 FieldBuilder.SetConstant (ConstantValue);
354 if (!TypeManager.RegisterFieldValue (FieldBuilder, ConstantValue))
355 throw new Exception ("Cannot register const value");
357 value = ConstantValue;
368 /// Emits the field value by evaluating the expression
370 public void EmitConstant (TypeContainer parent)
372 EmitContext ec = new EmitContext (parent, Location, null, type, ModFlags);
374 LookupConstantValue (out value,ec);
379 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb)
381 FieldBuilder.SetCustomAttribute (cb);