// 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 Nova.Parsing;
namespace Nova.CodeDOM
{
/// <summary>
/// Declares a struct, includes a name plus a body, along with various optional modifiers.
/// Unlike classes, structs are value types.
/// </summary>
/// <remarks>
/// Non-nested structs can be only public or internal, and default to internal.
/// Nested structs can be any of the 5 access types, and default to private.
/// Other valid modifiers include: new, partial
/// Members of a struct default to private, and can't be either of the 2 protected options.
/// Allowed members are: same as classes, except NO default constructor and NO destructor.
/// Initializing instance fields isn't allowed.
/// Structs can be created without using new, in which case the object can't be used until
/// all fields are initialized.
/// Inheritance isn't allowed, but implementing interfaces is OK.
/// The optional base list can contain one or more interfaces, but NOT any structs.
/// Structs are not permitted to declare a parameterless constructor - instead, the compiler implicitly
/// generates one that sets all value-type fields to their default value, and all references to null.
/// </remarks>
public class StructDecl : BaseListTypeDecl
{
#region /* CONSTRUCTORS */
/// <summary>
/// Create a <see cref="StructDecl"/> with the specified name.
/// </summary>
public StructDecl(string name, Modifiers modifiers)
: base(name, modifiers)
{ }
/// <summary>
/// Create a <see cref="StructDecl"/> with the specified name.
/// </summary>
public StructDecl(string name)
: base(name, Modifiers.None)
{ }
/// <summary>
/// Create a <see cref="StructDecl"/> with the specified name, modifiers, and type parameters.
/// </summary>
public StructDecl(string name, Modifiers modifiers, params TypeParameter[] typeParameters)
: base(name, modifiers, typeParameters)
{ }
/// <summary>
/// Create a <see cref="StructDecl"/> with the specified name, modifiers, and base types.
/// </summary>
public StructDecl(string name, Modifiers modifiers, params Expression[] baseTypes)
: base(name, modifiers, baseTypes)
{ }
#endregion
#region /* PROPERTIES */
/// <summary>
/// Always <c>true</c>.
/// </summary>
public override bool IsStruct
{
get { return true; }
}
/// <summary>
/// Always <c>true</c>.
/// </summary>
public override bool IsValueType
{
get { return true; }
}
/// <summary>
/// The keyword associated with the <see cref="Statement"/>.
/// </summary>
public override string Keyword
{
get { return ParseToken; }
}
#endregion
#region /* METHODS */
/// <summary>
/// Get the base type.
/// </summary>
public override TypeRef GetBaseType()
{
return TypeRef.ValueTypeRef;
}
#endregion
#region /* PARSING */
/// <summary>
/// The token used to parse the code object.
/// </summary>
public new const string ParseToken = "struct";
internal static void AddParsePoints()
{
// Structs are only valid with a Namespace or TypeDecl parent, but we'll allow any IBlock so that we can
// properly parse them if they accidentally end up at the wrong level (only to flag them as errors).
// This also allows for them to be embedded in a DocCode object.
Parser.AddParsePoint(ParseToken, Parse, typeof(IBlock));
}
/// <summary>
/// Parse a <see cref="StructDecl"/>.
/// </summary>
public static StructDecl Parse(Parser parser, CodeObject parent, ParseFlags flags)
{
return new StructDecl(parser, parent);
}
protected StructDecl(Parser parser, CodeObject parent)
: base(parser, parent)
{
MoveComments(parser.LastToken); // Get any comments before 'struct'
parser.NextToken(); // Move past 'struct'
ParseNameTypeParameters(parser); // Parse the name and any optional type parameters
ParseModifiersAndAnnotations(parser); // Parse any attributes and/or modifiers
// Move any trailing compiler directives to the Infix1 position (assume we have a base-type list)
MoveAnnotations(AnnotationFlags.IsPostfix, AnnotationFlags.IsInfix1);
ParseBaseTypeList(parser); // Parse the optional base-type list
ParseConstraintClauses(parser); // Parse any constraint clauses
// Move any trailing post annotations on the last base type to the first constraint (if any)
AdjustBaseTypePostComments();
// If we don't have a base-type list, move any trailing compiler directives to the Postfix position
if (_baseTypes == null || _baseTypes.Count == 0)
MoveAnnotations(AnnotationFlags.IsInfix1, AnnotationFlags.IsPostfix);
new Block(out _body, parser, this, true); // Parse the body
// Eat any trailing terminator (they are allowed but not required on non-delegate type declarations)
if (parser.TokenText == ParseTokenTerminator)
parser.NextToken();
}
#endregion
#region /* FORMATTING */
/// <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 a struct declaration
return 2;
}
#endregion
}
}