// 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;
using Nova.Resolving;
namespace Nova.CodeDOM
{
/// <summary>
/// Represents a "property" - a virtual field accessed only by calling get and/or set methods.
/// </summary>
public class PropertyDecl : PropertyDeclBase
{
#region /* CONSTRUCTORS */
/// <summary>
/// Create a <see cref="PropertyDecl"/> with the specified name, type, and modifiers.
/// </summary>
public PropertyDecl(string name, Expression type, Modifiers modifiers)
: base(name, type, modifiers)
{ }
/// <summary>
/// Create a <see cref="PropertyDecl"/> with the specified name and type.
/// </summary>
public PropertyDecl(string name, Expression type)
: base(name, type, Modifiers.None)
{ }
/// <summary>
/// Create a <see cref="PropertyDecl"/> with the specified name and type.
/// </summary>
public PropertyDecl(Expression name, Expression type)
: base(name, type, Modifiers.None)
{ }
#endregion
#region /* PROPERTIES */
/// <summary>
/// The descriptive category of the code object.
/// </summary>
public override string Category
{
get { return "property"; }
}
/// <summary>
/// True if the property has a getter method.
/// </summary>
public bool HasGetter
{
get { return (_body.FindFirst<GetterDecl>() != null); }
}
/// <summary>
/// True if the property has a setter method.
/// </summary>
public bool HasSetter
{
get { return (_body.FindFirst<SetterDecl>() != null); }
}
/// <summary>
/// The 'getter' method for the property.
/// </summary>
public GetterDecl Getter
{
get { return _body.FindFirst<GetterDecl>(); }
set
{
if (_body != null)
{
GetterDecl existing = _body.FindFirst<GetterDecl>();
if (existing != null)
_body.Remove(existing);
}
Insert(0, value); // Always put the 'getter' first
}
}
/// <summary>
/// The 'setter' method for the property.
/// </summary>
public SetterDecl Setter
{
get { return _body.FindFirst<SetterDecl>(); }
set
{
if (_body != null)
{
SetterDecl existing = _body.FindFirst<SetterDecl>();
if (existing != null)
_body.Remove(existing);
}
int pos = (_body != null ? _body.Count : 0);
Insert(pos, value); // Always put the 'setter' after any 'getter'
}
}
/// <summary>
/// True if the property is readable.
/// </summary>
public override bool IsReadable { get { return HasGetter; } }
/// <summary>
/// True if the property is writable.
/// </summary>
public override bool IsWritable { get { return HasSetter; } }
#endregion
#region /* METHODS */
/// <summary>
/// Create a reference to the <see cref="PropertyDecl"/>.
/// </summary>
/// <param name="isFirstOnLine">True if the reference should be displayed on a new line.</param>
/// <returns>A <see cref="PropertyRef"/>.</returns>
public override SymbolicRef CreateRef(bool isFirstOnLine)
{
return new PropertyRef(this, isFirstOnLine);
}
/// <summary>
/// Get the IsPrivate access right for the specified usage, and if not private then also get the IsProtected and IsInternal rights.
/// </summary>
/// <param name="isTargetOfAssignment">Usage - true if the target of an assignment ('lvalue'), otherwise false.</param>
/// <param name="isPrivate">True if the access is private.</param>
/// <param name="isProtected">True if the access is protected.</param>
/// <param name="isInternal">True if the access is internal.</param>
public override void GetAccessRights(bool isTargetOfAssignment, out bool isPrivate, out bool isProtected, out bool isInternal)
{
isPrivate = isProtected = isInternal = false;
// The access rights of a property actually depend on the rights of the corresponding
// getter/setter, depending upon whether we're assigning to it or not.
if (isTargetOfAssignment)
{
SetterDecl setterDecl = Setter;
if (setterDecl != null)
{
isPrivate = setterDecl.IsPrivate;
if (!isPrivate)
{
isProtected = setterDecl.IsProtected;
isInternal = setterDecl.IsInternal;
}
}
}
else
{
GetterDecl getterDecl = Getter;
if (getterDecl != null)
{
isPrivate = getterDecl.IsPrivate;
if (!isPrivate)
{
isProtected = getterDecl.IsProtected;
isInternal = getterDecl.IsInternal;
}
}
}
}
#endregion
#region /* PARSING */
/// <summary>
/// Parse a <see cref="PropertyDecl"/>.
/// </summary>
public PropertyDecl(Parser parser, CodeObject parent)
: base(parser, parent, true)
{ }
#endregion
#region /* RESOLVING */
/// <summary>
/// Resolve all child symbolic references, using the specified <see cref="ResolveCategory"/> and <see cref="ResolveFlags"/>.
/// </summary>
public override CodeObject Resolve(ResolveCategory resolveCategory, ResolveFlags flags)
{
if ((flags & (ResolveFlags.Phase1 | ResolveFlags.Phase3)) == 0)
{
if (_type != null)
_type = (Expression)_type.Resolve(ResolveCategory.Type, flags);
if (_name is Expression)
_name = ((Expression)_name).Resolve(ResolveCategory.Property, flags);
}
if ((flags & (ResolveFlags.Phase1 | ResolveFlags.Phase2)) == 0)
{
ResolveAttributes(flags);
if (_body != null)
_body.Resolve(ResolveCategory.CodeObject, flags);
ResolveDocComments(flags);
}
return this;
}
#endregion
}
}