//
// const.cs: Constant declarations.
//
// Author:
// Miguel de Icaza (miguel@ximian.com)
// Marek Safar (marek.safar@seznam.cz)
//
// (C) 2001 Ximian, Inc.
//
//
namespace Mono.CSharp {
using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Collections;
public interface IConstant
{
void CheckObsoleteness (Location loc);
bool ResolveValue ();
Constant Value { get; }
}
public class Const : FieldMember, IConstant {
Expression Expr;
Constant value;
bool in_transit;
public const int AllowedModifiers =
Modifiers.NEW |
Modifiers.PUBLIC |
Modifiers.PROTECTED |
Modifiers.INTERNAL |
Modifiers.PRIVATE;
public Const (TypeContainer parent, Expression constant_type, string name,
Expression expr, int mod_flags, Attributes attrs, Location loc)
: base (parent, constant_type, mod_flags, AllowedModifiers,
new MemberName (name, loc), expr, attrs)
{
Expr = expr;
ModFlags |= Modifiers.STATIC;
}
protected override bool CheckBase ()
{
// Constant.Define can be called when the parent type hasn't yet been populated
// and it's base types need not have been populated. So, we defer this check
// to the second time Define () is called on this member.
if (Parent.BaseCache == null)
return true;
return base.CheckBase ();
}
///
/// Defines the constant in the @parent
///
public override bool Define ()
{
// Make Define () idempotent, but ensure that the error check happens.
if (FieldBuilder != null)
return base.CheckBase ();
if (!base.Define ())
return false;
Type ttype = MemberType;
while (ttype.IsArray)
ttype = TypeManager.GetElementType (ttype);
FieldAttributes field_attr = FieldAttributes.Static | Modifiers.FieldAttr (ModFlags);
// Decimals cannot be emitted into the constant blob. So, convert to 'readonly'.
if (ttype == TypeManager.decimal_type) {
field_attr |= FieldAttributes.InitOnly;
Parent.RegisterFieldForInitialization (this);
}
else {
field_attr |= FieldAttributes.Literal;
}
FieldBuilder = Parent.TypeBuilder.DefineField (Name, MemberType, field_attr);
TypeManager.RegisterConstant (FieldBuilder, this);
return true;
}
///
/// Emits the field value by evaluating the expression
///
public override void Emit ()
{
if (!ResolveValue ())
return;
if (value.Type == TypeManager.decimal_type) {
Decimal d = ((DecimalConstant)value).Value;
int[] bits = Decimal.GetBits (d);
object[] args = new object[] { (byte)(bits [3] >> 16), (byte)(bits [3] >> 31), (uint)bits [2], (uint)bits [1], (uint)bits [0] };
CustomAttributeBuilder cab = new CustomAttributeBuilder (TypeManager.decimal_constant_attribute_ctor, args);
FieldBuilder.SetCustomAttribute (cab);
}
else{
FieldBuilder.SetConstant (value.GetTypedValue ());
}
base.Emit ();
}
public static void Error_ExpressionMustBeConstant (Location loc, string e_name)
{
Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
}
public static void Error_CyclicDeclaration (MemberCore mc)
{
Report.Error (110, mc.Location, "The evaluation of the constant value for `{0}' involves a circular definition",
mc.GetSignatureForError ());
}
#region IConstant Members
public bool ResolveValue ()
{
if (value != null)
return true;
SetMemberIsUsed ();
if (in_transit) {
Error_CyclicDeclaration (this);
// Suppress cyclic errors
value = New.Constantify (MemberType);
return false;
}
in_transit = true;
EmitContext ec = new EmitContext (Parent, Location, null, MemberType, ModFlags);
value = Expr.ResolveAsConstant (ec, this);
if (value == null)
return false;
value = value.ToType (MemberType, Location);
if (value == null)
return false;
in_transit = false;
return true;
}
public Constant Value {
get {
return value;
}
}
#endregion
}
public class ExternalConstant: IConstant
{
FieldInfo fi;
Constant value;
public ExternalConstant (FieldInfo fi)
{
this.fi = fi;
}
#region IConstant Members
public void CheckObsoleteness (Location loc)
{
ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (fi);
if (oa == null) {
return;
}
AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (fi), loc);
}
public bool ResolveValue ()
{
if (value != null)
return true;
if (fi.DeclaringType.IsEnum) {
value = Expression.Constantify (fi.GetValue (fi), TypeManager.EnumToUnderlying (fi.FieldType));
value = new EnumConstant (value, fi.DeclaringType);
return true;
}
value = Expression.Constantify (fi.GetValue (fi), fi.FieldType);
return true;
}
public Constant Value {
get {
return value;
}
}
#endregion
}
}