// Copyright 2005-2015 Giacomo Stelluti Scala & Contributors. All rights reserved. See License.md in the project root for license information. using System; using System.Collections.Generic; using System.Linq; namespace CommandLine { /// /// Discriminator enumeration of derivates. /// public enum ErrorType { /// /// Value of type. /// BadFormatTokenError, /// /// Value of type. /// MissingValueOptionError, /// /// Value of type. /// UnknownOptionError, /// /// Value of type. /// MissingRequiredOptionError, /// /// Value of type. /// MutuallyExclusiveSetError, /// /// Value of type. /// BadFormatConversionError, /// /// Value of type. /// SequenceOutOfRangeError, /// /// Value of type. /// RepeatedOptionError, /// /// Value of type. /// NoVerbSelectedError, /// /// Value of type. /// BadVerbSelectedError, /// /// Value of type. /// HelpRequestedError, /// /// Value of type. /// HelpVerbRequestedError, /// /// Value of type. /// VersionRequestedError, /// /// Value of type. /// SetValueExceptionError, /// /// Value of type. /// InvalidAttributeConfigurationError, /// /// Value of type. /// MissingGroupOptionError, /// /// Value of type. /// GroupOptionAmbiguityError, /// /// Value of type. /// MultipleDefaultVerbsError } /// /// Base type of all errors. /// /// All errors are defined within the system. There's no reason to create custom derivate types. public abstract class Error : IEquatable { private readonly ErrorType tag; private readonly bool stopsProcessing; /// /// Initializes a new instance of the class. /// /// Type discriminator tag. /// Tells if error stops parsing process. protected internal Error(ErrorType tag, bool stopsProcessing) { this.tag = tag; this.stopsProcessing = stopsProcessing; } /// /// Initializes a new instance of the class. /// /// Type discriminator tag. protected internal Error(ErrorType tag) : this(tag, false) { } /// /// Error type discriminator, defined as enumeration. /// public ErrorType Tag { get { return tag; } } /// /// Tells if error stops parsing process. /// Filtered by . /// public bool StopsProcessing { get { return stopsProcessing; } } /// /// Determines whether the specified is equal to the current . /// /// The to compare with the current . /// true if the specified is equal to the current ; otherwise, false. public override bool Equals(object obj) { var other = obj as Error; if (other != null) { return Equals(other); } return base.Equals(obj); } /// /// Serves as a hash function for a particular type. /// /// A hash code for the current . public override int GetHashCode() { return new { Tag, StopsProcessing }.GetHashCode(); } /// /// Returns a value that indicates whether the current instance and a specified have the same value. /// /// The instance to compare. /// true if this instance of and have the same value; otherwise, false. public bool Equals(Error other) { if (other == null) { return false; } return Tag.Equals(other.Tag); } } /// /// Base type of all errors related to bad token detection. /// public abstract class TokenError : Error, IEquatable { private readonly string token; /// /// Initializes a new instance of the class. /// /// Error type. /// Problematic token. protected internal TokenError(ErrorType tag, string token) : base(tag) { if (token == null) throw new ArgumentNullException("token"); this.token = token; } /// /// The string containing the token text. /// public string Token { get { return token; } } /// /// Determines whether the specified is equal to the current . /// /// The to compare with the current . /// true if the specified is equal to the current ; otherwise, false. public override bool Equals(object obj) { var other = obj as TokenError; if (other != null) { return Equals(other); } return base.Equals(obj); } /// /// Serves as a hash function for a particular type. /// /// A hash code for the current . public override int GetHashCode() { return new { Tag, StopsProcessing, Token }.GetHashCode(); } /// /// Returns a value that indicates whether the current instance and a specified have the same value. /// /// The instance to compare. /// true if this instance of and have the same value; otherwise, false. public bool Equals(TokenError other) { if (other == null) { return false; } return Tag.Equals(other.Tag) && Token.Equals(other.Token); } } /// /// Models an error generated when an invalid token is detected. /// public sealed class BadFormatTokenError : TokenError { internal BadFormatTokenError(string token) : base(ErrorType.BadFormatTokenError, token) { } } /// /// Base type of all erros with name information. /// public abstract class NamedError : Error, IEquatable { private readonly NameInfo nameInfo; /// /// Initializes a new instance of the class. /// /// Error type. /// Problematic name. protected internal NamedError(ErrorType tag, NameInfo nameInfo) : base(tag) { this.nameInfo = nameInfo; } /// /// Name information relative to this error instance. /// public NameInfo NameInfo { get { return nameInfo; } } /// /// Determines whether the specified is equal to the current . /// /// The to compare with the current . /// true if the specified is equal to the current ; otherwise, false. public override bool Equals(object obj) { var other = obj as NamedError; if (other != null) { return Equals(other); } return base.Equals(obj); } /// /// Serves as a hash function for a particular type. /// /// A hash code for the current . public override int GetHashCode() { return new { Tag, StopsProcessing, NameInfo }.GetHashCode(); } /// /// Returns a value that indicates whether the current instance and a specified have the same value. /// /// The instance to compare. /// true if this instance of and have the same value; otherwise, false. public bool Equals(NamedError other) { if (other == null) { return false; } return Tag.Equals(other.Tag) && NameInfo.Equals(other.NameInfo); } } /// /// Models an error generated when an option lacks its value. /// public sealed class MissingValueOptionError : NamedError { internal MissingValueOptionError(NameInfo nameInfo) : base(ErrorType.MissingValueOptionError, nameInfo) { } } /// /// Models an error generated when an unknown option is detected. /// public sealed class UnknownOptionError : TokenError { internal UnknownOptionError(string token) : base(ErrorType.UnknownOptionError, token) { } } /// /// Models an error generated when a required option is required. /// public sealed class MissingRequiredOptionError : NamedError { internal MissingRequiredOptionError(NameInfo nameInfo) : base(ErrorType.MissingRequiredOptionError, nameInfo) { } } /// /// Models an error generated when a an option from another set is defined. /// public sealed class MutuallyExclusiveSetError : NamedError { private readonly string setName; internal MutuallyExclusiveSetError(NameInfo nameInfo, string setName) : base(ErrorType.MutuallyExclusiveSetError, nameInfo) { this.setName = setName; } /// /// Option's set name. /// public string SetName { get { return setName; } } } /// /// Models an error generated when a value conversion fails. /// public sealed class BadFormatConversionError : NamedError { internal BadFormatConversionError(NameInfo nameInfo) : base(ErrorType.BadFormatConversionError, nameInfo) { } } /// /// Models an error generated when a sequence value lacks elements. /// public sealed class SequenceOutOfRangeError : NamedError { internal SequenceOutOfRangeError(NameInfo nameInfo) : base(ErrorType.SequenceOutOfRangeError, nameInfo) { } } /// /// Models an error generated when an option is repeated two or more times. /// public sealed class RepeatedOptionError : NamedError { internal RepeatedOptionError(NameInfo nameInfo) : base(ErrorType.RepeatedOptionError, nameInfo) { } } /// /// Models an error generated when an unknown verb is detected. /// public sealed class BadVerbSelectedError : TokenError { internal BadVerbSelectedError(string token) : base(ErrorType.BadVerbSelectedError, token) { } } /// /// Models an error generated when a user explicitly requests help. /// public sealed class HelpRequestedError : Error { internal HelpRequestedError() : base(ErrorType.HelpRequestedError, true) { } } /// /// Models an error generated when a user explicitly requests help in verb commands scenario. /// public sealed class HelpVerbRequestedError : Error { private readonly string verb; private readonly Type type; private readonly bool matched; internal HelpVerbRequestedError(string verb, Type type, bool matched) : base(ErrorType.HelpVerbRequestedError, true) { this.verb = verb; this.type = type; this.matched = matched; } /// /// Verb command string. /// public string Verb { get { return verb; } } /// /// of verb command. /// public Type Type { get { return type; } } /// /// true if verb command is found; otherwise false. /// public bool Matched { get { return matched; } } } /// /// Models an error generated when no verb is selected. /// public sealed class NoVerbSelectedError : Error { internal NoVerbSelectedError() : base(ErrorType.NoVerbSelectedError) { } } /// /// Models an error generated when a user explicitly requests version. /// public sealed class VersionRequestedError : Error { internal VersionRequestedError() : base(ErrorType.VersionRequestedError, true) { } } /// /// Models as error generated when exception is thrown at Property.SetValue /// public sealed class SetValueExceptionError : NamedError { private readonly Exception exception; private readonly object value; internal SetValueExceptionError(NameInfo nameInfo, Exception exception, object value) : base(ErrorType.SetValueExceptionError, nameInfo) { this.exception = exception; this.value = value; } /// /// The expection thrown from Property.SetValue /// public Exception Exception { get { return exception; } } /// /// The value that had to be set to the property /// public object Value { get { return value; } } } /// /// Models an error generated when an invalid token is detected. /// public sealed class InvalidAttributeConfigurationError : Error { public const string ErrorMessage = "Check if Option or Value attribute values are set properly for the given type."; internal InvalidAttributeConfigurationError() : base(ErrorType.InvalidAttributeConfigurationError, true) { } } public sealed class MissingGroupOptionError : Error, IEquatable, IEquatable { public const string ErrorMessage = "At least one option in a group must have value."; private readonly string group; private readonly IEnumerable names; internal MissingGroupOptionError(string group, IEnumerable names) : base(ErrorType.MissingGroupOptionError) { this.group = group; this.names = names; } public string Group { get { return group; } } public IEnumerable Names { get { return names; } } public new bool Equals(Error obj) { var other = obj as MissingGroupOptionError; if (other != null) { return Equals(other); } return base.Equals(obj); } public bool Equals(MissingGroupOptionError other) { if (other == null) { return false; } return Group.Equals(other.Group) && Names.SequenceEqual(other.Names); } } public sealed class GroupOptionAmbiguityError : NamedError { public NameInfo Option; internal GroupOptionAmbiguityError(NameInfo option) : base(ErrorType.GroupOptionAmbiguityError, option) { Option = option; } } /// /// Models an error generated when multiple default verbs are defined. /// public sealed class MultipleDefaultVerbsError : Error { public const string ErrorMessage = "More than one default verb is not allowed."; internal MultipleDefaultVerbsError() : base(ErrorType.MultipleDefaultVerbsError) { } } }