// The Nova Project by Ken Beckett.
// Copyright (C) 2007-2012 Inevitable Software, all rights reserved.
// Released under the Common Development and Distribution License, CDDL-1.0: http://opensource.org/licenses/cddl1.php
using System.Collections.Generic;
using Nova.Utilities;
namespace Nova.CodeDOM
{
/// <summary>
/// Declares an enumerated type, and includes a name and a body with a list of identifiers
/// (with optional assigned values). It can also optionally have modifiers and/or a base type.
/// </summary>
/// <remarks>
/// Non-nested enums can be only public or internal, and default to internal.
/// Nested enums can be any of the 5 access types, and default to private.
/// Other valid modifiers include: new
/// Allowable base types are: byte, sbyte, short, ushort, int (default), uint, long, ulong
/// Enums contain zero or more identifiers as members, which are assigned constant
/// values which default to 0 and auto-increment. Alternatively, constant expressions
/// may be used to manually assign values.
/// </remarks>
public class EnumDecl : BaseListTypeDecl
{
#region /* CONSTRUCTORS */
/// <summary>
/// Create an <see cref="EnumDecl"/> with the specified name.
/// </summary>
public EnumDecl(string name, Modifiers modifiers)
: base(name, modifiers)
{ }
/// <summary>
/// Create an <see cref="EnumDecl"/> with the specified name.
/// </summary>
public EnumDecl(string name)
: base(name, Modifiers.None)
{ }
/// <summary>
/// Create an <see cref="EnumDecl"/> with the specified name, modifiers, and base type.
/// </summary>
public EnumDecl(string name, Modifiers modifiers, Expression baseType)
: base(name, modifiers, baseType)
{ }
/// <summary>
/// Create an <see cref="EnumDecl"/> with the specified name and base type.
/// </summary>
public EnumDecl(string name, Expression baseType)
: base(name, Modifiers.None, baseType)
{ }
#endregion
#region /* PROPERTIES */
/// <summary>
/// Always <c>true</c> for an enum.
/// </summary>
public override bool IsStatic
{
get { return true; }
}
/// <summary>
/// Always <c>true</c> for an enum.
/// </summary>
public override bool IsEnum
{
get { return true; }
}
/// <summary>
/// Always <c>false</c> for an enum.
/// </summary>
public override bool IsGenericType
{
get { return false; }
}
/// <summary>
/// Always <c>true</c> for an enum.
/// </summary>
public override bool IsValueType
{
get { return true; }
}
/// <summary>
/// True if this is a bit-flag type enum, otherwise false.
/// </summary>
public bool IsBitFlags
{
get { return HasAttribute(TypeUtil.FlagsAttributeName); }
set
{
bool isBitFlags = IsBitFlags;
if (value)
{
// Add the Flags attribute if it doesn't already exist
if (!isBitFlags)
AttachAnnotation(new Attribute((TypeRef)TypeRef.FlagsAttributeRef.Clone()));
}
else
{
// Remove any existing Flags attribute
if (isBitFlags)
RemoveAttribute(TypeUtil.FlagsAttributeName);
}
}
}
/// <summary>
/// The underlying type of the enum (will never be null - defaults to 'int').
/// </summary>
public Expression UnderlyingType
{
get
{
// Any non-default underlying (storage) type is actually stored as the base type, because
// the syntax appears that way, but the real base type is always System.Enum. Also, the
// underlying type must be a primitive integral type, not a user-defined type. If no
// storage type is specified, the default is 'int'.
Expression type = null;
if (HasBaseTypes)
type = BaseTypes[0];
return (type ?? TypeRef.IntRef);
}
set
{
// Clear the base type if 'int', otherwise create it or update any existing one
if (value == null)
_baseTypes = null;
else
{
TypeRefBase typeRefBase = value.SkipPrefixes() as TypeRefBase;
if (typeRefBase != null && typeRefBase.IsSameRef(TypeRef.IntRef))
_baseTypes = null;
else
_baseTypes = new ChildList<Expression>(this) { value };
}
}
}
/// <summary>
/// The child MultiEnumMemberDecl object that in turn holds all of the EnumMemberDecls.
/// </summary>
public MultiEnumMemberDecl MultiEnumMemberDecl
{
get
{
// Return the first existing MultiEnumMemberDecl (should be only one)
MultiEnumMemberDecl valueDecl = _body.FindFirst<MultiEnumMemberDecl>();
if (valueDecl != null)
return valueDecl;
// If none was found, create one now
valueDecl = new MultiEnumMemberDecl();
_body.Add(valueDecl);
return valueDecl;
}
}
/// <summary>
/// The EnumMemberDecl grandchildren of the EnumDecl (from the MultiEnumMemberDecl child object).
/// </summary>
public ChildList<EnumMemberDecl> MemberDecls
{
get { return MultiEnumMemberDecl.MemberDecls; }
}
/// <summary>
/// The keyword associated with the <see cref="Statement"/>.
/// </summary>
public override string Keyword
{
get { return "enum"; }
}
#endregion
#region /* METHODS */
/// <summary>
/// Add an <see cref="EnumMemberDecl"/>.
/// </summary>
public void Add(EnumMemberDecl enumMemberDecl)
{
MultiEnumMemberDecl.Add(enumMemberDecl);
}
/// <summary>
/// Add an <see cref="EnumMemberDecl"/> with the specified name.
/// </summary>
public void Add(string name, Expression initialization)
{
MultiEnumMemberDecl.Add(name, initialization);
}
/// <summary>
/// Add an <see cref="EnumMemberDecl"/> with the specified name.
/// </summary>
public void Add(string name)
{
MultiEnumMemberDecl.Add(name, null);
}
/// <summary>
/// Add multiple <see cref="EnumMemberDecl"/>s.
/// </summary>
public void Add(params EnumMemberDecl[] enumMemberDecls)
{
MultiEnumMemberDecl.AddRange(enumMemberDecls);
}
/// <summary>
/// Add a collection of <see cref="EnumMemberDecl"/>s.
/// </summary>
public void AddRange(IEnumerable<EnumMemberDecl> collection)
{
MultiEnumMemberDecl.AddRange(collection);
}
/// <summary>
/// Get the base type.
/// </summary>
public override TypeRef GetBaseType()
{
// The base type is *always* Enum, NOT the underlying type
return TypeRef.EnumRef;
}
/// <summary>
/// Get the enum member with the specified name.
/// </summary>
public EnumMemberRef GetMember(string name)
{
return MultiEnumMemberDecl.GetMember(name);
}
#endregion
#region /* FORMATTING */
/// <summary>
/// True if the code object only requires a single line for display by default.
/// </summary>
public override bool IsSingleLineDefault
{
get { return true; }
}
/// <summary>
/// Determine a default of 1 or 2 newlines when adding items to a <see cref="Block"/>.
/// </summary>
public override int DefaultNewLines(CodeObject previous)
{
// Always default to a blank line before an enum declaration
return 2;
}
#endregion
}
}