//
// Author: Miguel de Icaza (miguel@gnu.org)
// Ravi Pratap (ravi@ximian.com)
+// Anirban Bhattacharjee (banirban@novell.com)
+// Jambunathan K (kjambunathan@novell.com)
//
// Licensed under the terms of the GNU GPL
//
namespace Mono.MonoBASIC {
+ public class EnumMember : MemberCore
+ {
+ Enum parent_enum;
+ Expression expr;
+ int index;
+
+ FieldBuilder builder;
+ object enum_value;
+
+ bool in_transit = false;
+ FieldAttributes field_attrs = FieldAttributes.Public | FieldAttributes.Static
+ | FieldAttributes.Literal;
+
+ public EnumMember (Enum parent_enum, Expression expr, string name,
+ Location loc, Attributes attrs, int index):
+ base (name, attrs, loc)
+ {
+ this.parent_enum = parent_enum;
+ this.expr = expr;
+ this.index = index;
+ }
+
+ public override void ApplyAttributeBuilder(Attribute a, CustomAttributeBuilder cb)
+ {
+ builder.SetCustomAttribute (cb);
+ }
+
+ public override AttributeTargets AttributeTargets {
+ get {
+ return AttributeTargets.Field;
+ }
+ }
+
+ public override bool Define (TypeContainer tc)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public object GetValue ()
+ {
+ if (builder == null)
+ DefineMember ();
+
+ return enum_value;
+ }
+
+ public FieldBuilder DefineMember ()
+ {
+ if (builder != null)
+ return builder;
+
+ DoDefineMember ();
+
+ if (builder == null)
+ parent_enum.RemoveEnumMember (this.Name);
+
+ return builder;
+ }
+
+ public FieldBuilder DoDefineMember ()
+ {
+ object default_value = null;
+ Constant c = null;
+ Type UnderlyingType = parent_enum.UnderlyingType;
+ EmitContext ec = parent_enum.EmitContext;
+
+ default_value = enum_value;
+
+ if (in_transit) {
+ Report.Error (30500, Location, "The evaluation of the constant value for `" +
+ parent_enum.Name + "." + Name + "' involves a circular definition.");
+ return null;
+ }
+
+ //
+ // So if the above doesn't happen, we have a member that is undefined
+ // We now proceed to define it
+ //
+ Expression val = expr;
+ int idx = index;
+
+ if (val == null) {
+ if (idx == 0)
+ default_value = 0;
+ else {
+ int i = idx - 1;
+ EnumMember em = parent_enum [i];
+
+ in_transit = true;
+ default_value = em.GetValue ();
+ in_transit = false;
+
+ if (default_value == null)
+ return null;
+
+ default_value = Enum.GetNextDefaultValue (default_value, UnderlyingType);
+ }
+
+ } else {
+ bool old = ec.InEnumContext;
+ ec.InEnumContext = true;
+ in_transit = true;
+ val = val.Resolve (ec);
+ in_transit = false;
+ ec.InEnumContext = old;
+
+ if (val == null)
+ return null;
+
+ if (! Enum.IsValidEnumConstant (val)) {
+ Report.Error (
+ 30650, Location,
+ "Type byte, sbyte, short, ushort, int, uint, long, or " +
+ "ulong expected (have: " + val + ")");
+ return null;
+ }
+
+ c = (Constant) val;
+
+ default_value = c.GetValue ();
+
+ if (default_value == null) {
+ Enum.Error_ConstantValueCannotBeConverted (c, Location, UnderlyingType);
+ return null;
+ }
+ }
+
+ builder = parent_enum.TypeBuilder.DefineField (Name, parent_enum.TypeBuilder, field_attrs);
+
+ try {
+ //FXME: ChangeType is not the right thing to do.
+ default_value = TypeManager.ChangeType (default_value, UnderlyingType);
+ } catch {
+ Enum.Error_ConstantValueCannotBeConverted (c, Location, UnderlyingType);
+ return null;
+ }
+
+ enum_value = default_value;
+
+ builder.SetConstant (enum_value);
+
+ if (!TypeManager.RegisterFieldValue (builder, enum_value))
+ return null;
+
+ if (OptAttributes != null)
+ OptAttributes.Emit (ec, this);
+
+ return builder;
+ }
+
+ }
+
+
/// <summary>
/// Enumeration container
/// </summary>
public class Enum : DeclSpace {
ArrayList ordered_enums;
-
public Expression BaseType;
- public Attributes OptAttributes;
-
public Type UnderlyingType;
-
- Hashtable member_to_location;
- Hashtable member_to_attributes;
-
- //
- // This is for members that have been defined
- //
- Hashtable member_to_value;
-
- //
- // This is used to mark members we're currently defining
- //
- Hashtable in_transit;
-
ArrayList field_builders;
public const int AllowedModifiers =
Modifiers.INTERNAL |
Modifiers.PRIVATE;
+ EmitContext emit_context;
+
public Enum (TypeContainer parent, Expression type, int mod_flags, string name, Attributes attrs, Location l)
- : base (parent, name, l)
+ : base (parent, name, attrs, l)
{
this.BaseType = type;
ModFlags = Modifiers.Check (AllowedModifiers, mod_flags,
- IsTopLevel ? Modifiers.INTERNAL : Modifiers.PRIVATE, l);
- OptAttributes = attrs;
+ IsTopLevel ? Modifiers.INTERNAL : Modifiers.PUBLIC, l);
ordered_enums = new ArrayList ();
- member_to_location = new Hashtable ();
- member_to_value = new Hashtable ();
- in_transit = new Hashtable ();
field_builders = new ArrayList ();
}
+ public override AttributeTargets AttributeTargets {
+ get {
+ return AttributeTargets.Enum;
+ }
+ }
+
/// <summary>
/// Adds @name to the enumeration space, with @expr
/// being its definition.
public AdditionResult AddEnumMember (string name, Expression expr, Location loc,
Attributes opt_attrs)
{
+ int index;
+ EnumMember em;
+
if (defined_names.Contains (name))
return AdditionResult.NameExists;
- DefineName (name, expr);
+ index = ordered_enums.Add (name);
+ em = new EnumMember (this, expr, name, loc, opt_attrs, index);
+ DefineName (name, em);
- ordered_enums.Add (name);
- member_to_location.Add (name, loc);
-
- if (member_to_attributes == null)
- member_to_attributes = new Hashtable ();
-
- member_to_attributes.Add (name, opt_attrs);
-
return AdditionResult.Success;
}
- //
- // This is used by corlib compilation: we map from our
- // type to a type that is consumable by the DefineField
- //
- Type MapToInternalType (Type t)
+ public void RemoveEnumMember (string name)
{
- if (t == TypeManager.int32_type)
- return typeof (int);
- if (t == TypeManager.int64_type)
- return typeof (long);
- if (t == TypeManager.uint32_type)
- return typeof (uint);
- if (t == TypeManager.uint64_type)
- return typeof (ulong);
- if (t == TypeManager.float_type)
- return typeof (float);
- if (t == TypeManager.double_type)
- return typeof (double);
- if (t == TypeManager.byte_type)
- return typeof (byte);
- if (t == TypeManager.sbyte_type)
- return typeof (sbyte);
- if (t == TypeManager.char_type)
- return typeof (char);
- if (t == TypeManager.short_type)
- return typeof (short);
- if (t == TypeManager.ushort_type)
- return typeof (ushort);
-
- throw new Exception ();
+ defined_names.Remove (name);
}
-
+
public override TypeBuilder DefineType ()
{
if (TypeBuilder != null)
return TypeBuilder;
+ emit_context = new EmitContext (Parent, this, Location, null,
+ UnderlyingType, ModFlags, false);
+
TypeAttributes attr = Modifiers.TypeAttr (ModFlags, IsTopLevel);
attr |= TypeAttributes.Class | TypeAttributes.Sealed;
UnderlyingType != TypeManager.ushort_type &&
UnderlyingType != TypeManager.byte_type &&
UnderlyingType != TypeManager.sbyte_type) {
- Report.Error (1008, Location,
+ Report.Error (30650, Location,
"Type byte, sbyte, short, ushort, int, uint, " +
"long, or ulong expected (got: " +
TypeManager.MonoBASIC_Name (UnderlyingType) + ")");
Basename, attr, TypeManager.enum_type);
}
- //
- // Call MapToInternalType for corlib
- //
TypeBuilder.DefineField ("value__", UnderlyingType,
FieldAttributes.Public | FieldAttributes.SpecialName
| FieldAttributes.RTSpecialName);
return TypeBuilder;
}
- bool IsValidEnumConstant (Expression e)
+ public static bool IsValidEnumConstant (Expression e)
{
if (!(e is Constant))
return false;
return false;
}
- object GetNextDefaultValue (object default_value)
+ static public object GetNextDefaultValue (object default_value, Type UnderlyingType)
{
if (UnderlyingType == TypeManager.int32_type) {
int i = (int) default_value;
return null;
}
- void Error_ConstantValueCannotBeConverted (object val, Location loc)
+ public static void Error_ConstantValueCannotBeConverted (object val, Location loc, Type UnderlyingType)
{
if (val is Constant)
- Report.Error (31, loc, "Constant value '" + ((Constant) val).AsString () +
+ Report.Error (30439, loc, "Constant value '" + ((Constant) val).AsString () +
"' cannot be converted" +
" to a " + TypeManager.MonoBASIC_Name (UnderlyingType));
else
- Report.Error (31, loc, "Constant value '" + val +
+ Report.Error (30439, loc, "Constant value '" + val +
"' cannot be converted" +
" to a " + TypeManager.MonoBASIC_Name (UnderlyingType));
return;
}
- /// <summary>
- /// Determines if a standard implicit conversion exists from
- /// expr_type to target_type
- /// </summary>
- public static bool ImplicitConversionExists (Type expr_type, Type target_type)
- {
- expr_type = TypeManager.TypeToCoreType (expr_type);
-
- if (expr_type == TypeManager.void_type)
- return false;
-
- if (expr_type == target_type)
- return true;
-
- // First numeric conversions
-
- if (expr_type == TypeManager.sbyte_type){
- //
- // From sbyte to short, int, long, float, double.
- //
- if ((target_type == TypeManager.int32_type) ||
- (target_type == TypeManager.int64_type) ||
- (target_type == TypeManager.double_type) ||
- (target_type == TypeManager.float_type) ||
- (target_type == TypeManager.short_type) ||
- (target_type == TypeManager.decimal_type))
- return true;
-
- } else if (expr_type == TypeManager.byte_type){
- //
- // From byte to short, ushort, int, uint, long, ulong, float, double
- //
- if ((target_type == TypeManager.short_type) ||
- (target_type == TypeManager.ushort_type) ||
- (target_type == TypeManager.int32_type) ||
- (target_type == TypeManager.uint32_type) ||
- (target_type == TypeManager.uint64_type) ||
- (target_type == TypeManager.int64_type) ||
- (target_type == TypeManager.float_type) ||
- (target_type == TypeManager.double_type) ||
- (target_type == TypeManager.decimal_type))
- return true;
-
- } else if (expr_type == TypeManager.short_type){
- //
- // From short to int, long, float, double
- //
- if ((target_type == TypeManager.int32_type) ||
- (target_type == TypeManager.int64_type) ||
- (target_type == TypeManager.double_type) ||
- (target_type == TypeManager.float_type) ||
- (target_type == TypeManager.decimal_type))
- return true;
-
- } else if (expr_type == TypeManager.ushort_type){
- //
- // From ushort to int, uint, long, ulong, float, double
- //
- if ((target_type == TypeManager.uint32_type) ||
- (target_type == TypeManager.uint64_type) ||
- (target_type == TypeManager.int32_type) ||
- (target_type == TypeManager.int64_type) ||
- (target_type == TypeManager.double_type) ||
- (target_type == TypeManager.float_type) ||
- (target_type == TypeManager.decimal_type))
- return true;
-
- } else if (expr_type == TypeManager.int32_type){
- //
- // From int to long, float, double
- //
- if ((target_type == TypeManager.int64_type) ||
- (target_type == TypeManager.double_type) ||
- (target_type == TypeManager.float_type) ||
- (target_type == TypeManager.decimal_type))
- return true;
-
- } else if (expr_type == TypeManager.uint32_type){
- //
- // From uint to long, ulong, float, double
- //
- if ((target_type == TypeManager.int64_type) ||
- (target_type == TypeManager.uint64_type) ||
- (target_type == TypeManager.double_type) ||
- (target_type == TypeManager.float_type) ||
- (target_type == TypeManager.decimal_type))
- return true;
-
- } else if ((expr_type == TypeManager.uint64_type) ||
- (expr_type == TypeManager.int64_type)) {
- //
- // From long/ulong to float, double
- //
- if ((target_type == TypeManager.double_type) ||
- (target_type == TypeManager.float_type) ||
- (target_type == TypeManager.decimal_type))
- return true;
-
- } else if (expr_type == TypeManager.char_type){
- //
- // From char to ushort, int, uint, long, ulong, float, double
- //
- if ((target_type == TypeManager.ushort_type) ||
- (target_type == TypeManager.int32_type) ||
- (target_type == TypeManager.uint32_type) ||
- (target_type == TypeManager.uint64_type) ||
- (target_type == TypeManager.int64_type) ||
- (target_type == TypeManager.float_type) ||
- (target_type == TypeManager.double_type) ||
- (target_type == TypeManager.decimal_type))
- return true;
-
- } else if (expr_type == TypeManager.float_type){
- //
- // float to double
- //
- if (target_type == TypeManager.double_type)
- return true;
- }
-
- return false;
- }
-
/// <summary>
/// This is used to lookup the value of an enum member. If the member is undefined,
/// it attempts to define it and return its value
/// </summary>
- public object LookupEnumValue (EmitContext ec, string name, Location loc)
+ public object LookupEnumValue (string name)
{
- object default_value = null;
- Constant c = null;
+ EnumMember em;
- default_value = member_to_value [name];
+ // first check whether the requested name is there
+ // in the member list of enum
- if (default_value != null)
- return default_value;
-
- //
- // This may happen if we're calling a method in System.Enum, for instance
- // Enum.IsDefined().
- //
- if (!defined_names.Contains (name))
- return null;
+ em = this [name];
- if (in_transit.Contains (name)) {
- Report.Error (110, loc, "The evaluation of the constant value for `" +
- Name + "." + name + "' involves a circular definition.");
+ if (em == null)
return null;
- }
-
- //
- // So if the above doesn't happen, we have a member that is undefined
- // We now proceed to define it
- //
- Expression val = this [name];
-
- if (val == null) {
-
- int idx = ordered_enums.IndexOf (name);
-
- if (idx == 0)
- default_value = 0;
- else {
- for (int i = 0; i < idx; ++i) {
- string n = (string) ordered_enums [i];
- Location m_loc = (Mono.MonoBASIC.Location)
- member_to_location [n];
- in_transit.Add (name, true);
- default_value = LookupEnumValue (ec, n, m_loc);
- in_transit.Remove (name);
- if (default_value == null)
- return null;
- }
-
- default_value = GetNextDefaultValue (default_value);
- }
-
- } else {
- bool old = ec.InEnumContext;
- ec.InEnumContext = true;
- in_transit.Add (name, true);
- val = val.Resolve (ec);
- in_transit.Remove (name);
- ec.InEnumContext = old;
-
- if (val == null)
- return null;
-
- if (!IsValidEnumConstant (val)) {
- Report.Error (
- 1008, loc,
- "Type byte, sbyte, short, ushort, int, uint, long, or " +
- "ulong expected (have: " + val + ")");
- return null;
- }
-
- c = (Constant) val;
- default_value = c.GetValue ();
-
- if (default_value == null) {
- Error_ConstantValueCannotBeConverted (c, loc);
- return null;
- }
-
- if (val is EnumConstant){
- Type etype = TypeManager.EnumToUnderlying (c.Type);
-
- if ( (!ImplicitConversionExists (etype, UnderlyingType)) &&
- (!Expression.RuntimeConversionExists (ec, val, UnderlyingType)) ){
- Expression.Error_CannotConvertImplicit (
- loc, c.Type, UnderlyingType);
- return null;
- }
- }
- }
-
- FieldAttributes attr = FieldAttributes.Public | FieldAttributes.Static
- | FieldAttributes.Literal;
- FieldBuilder fb = TypeBuilder.DefineField (name, UnderlyingType, attr);
-
- try {
- default_value = TypeManager.ChangeType (default_value, UnderlyingType);
- } catch {
- Error_ConstantValueCannotBeConverted (c, loc);
+ name = em.Name;
+ FieldBuilder fb = em.DefineMember ();
+
+ if (fb == null) {
return null;
- }
-
- fb.SetConstant (default_value);
- field_builders.Add (fb);
- member_to_value [name] = default_value;
+ }
- if (!TypeManager.RegisterFieldValue (fb, default_value))
- return null;
+ if (! field_builders.Contains (fb)) {
+ field_builders.Add (fb);
+ }
- //
- // Now apply attributes
- //
- Attribute.ApplyAttributes (ec, fb, fb, (Attributes) member_to_attributes [name], loc);
-
- return default_value;
+ return em.GetValue ();
}
public override bool DefineMembers (TypeContainer parent)
public override bool Define (TypeContainer parent)
{
- //
- // If there was an error during DefineEnum, return
- //
if (TypeBuilder == null)
return false;
-
+ /*
EmitContext ec = new EmitContext (parent, this, Location, null,
UnderlyingType, ModFlags, false);
-
- object default_value = 0;
-
- FieldAttributes attr = FieldAttributes.Public | FieldAttributes.Static
- | FieldAttributes.Literal;
-
-
+ */
foreach (string name in ordered_enums) {
- //
- // Have we already been defined, thanks to some cross-referencing ?
- //
- if (member_to_value.Contains (name))
- continue;
-
- Location loc = (Mono.MonoBASIC.Location) member_to_location [name];
-
- if (this [name] != null) {
- default_value = LookupEnumValue (ec, name, loc);
-
- if (default_value == null)
- return true;
+ EnumMember em = this [name];
+ FieldBuilder fb = em.DefineMember ();
- } else {
- FieldBuilder fb = TypeBuilder.DefineField (
- name, UnderlyingType, attr);
-
- if (default_value == null) {
- Report.Error (543, loc, "Enumerator value for '" + name + "' is too large to " +
- "fit in its type");
- return false;
- }
-
- try {
- default_value = TypeManager.ChangeType (default_value, UnderlyingType);
- } catch {
- Error_ConstantValueCannotBeConverted (default_value, loc);
- return false;
- }
+ if (fb == null) {
+ return false;
+ }
- fb.SetConstant (default_value);
+ if (!field_builders.Contains (fb)) {
field_builders.Add (fb);
- member_to_value [name] = default_value;
-
- if (!TypeManager.RegisterFieldValue (fb, default_value))
- return false;
-
- //
- // Apply attributes on the enum member
- //
- Attribute.ApplyAttributes (ec, fb, fb, (Attributes) member_to_attributes [name], loc);
}
-
- default_value = GetNextDefaultValue (default_value);
}
-
- Attribute.ApplyAttributes (ec, TypeBuilder, this, OptAttributes, Location);
+ if (OptAttributes != null)
+ OptAttributes.Emit (EmitContext, this);
+
return true;
}
ArrayList members = new ArrayList ();
if ((mt & MemberTypes.Field) != 0) {
+
+ if (criteria is string){
+ LookupEnumValue ((string) criteria);
+ }
+
foreach (FieldBuilder fb in field_builders)
if (filter (fb, criteria) == true)
members.Add (fb);
}
// indexer
- public Expression this [string name] {
+ public EnumMember this [string name] {
+ get {
+ EnumMember em = (EnumMember) defined_names [name];
+
+ if (em != null)
+ return em;
+
+ name = name.ToLower();
+ foreach (string nm in ordered_enums) {
+ if (nm.ToLower() == name) {
+ em = (EnumMember) defined_names [name];
+ break;
+ }
+ }
+
+ return em;
+ }
+ }
+
+ public EnumMember this[int mem_index] {
+ get {
+ string mem_name = (string) ordered_enums [mem_index];;
+ return (EnumMember) defined_names[mem_name];
+ }
+ }
+
+ public EmitContext EmitContext {
get {
- return (Expression) defined_names [name];
+ return emit_context;
}
}
}