public static T GetValueOrDefault <T>(this CommandResult commandResult)
        {
            var conversionResult = commandResult.ArgumentConversionResults
                                   .SingleOrDefault() ??
                                   ArgumentConversionResult.None(commandResult.ArgumentConversionResult.Argument);

            return(conversionResult
                   .ConvertIfNeeded(commandResult, typeof(T))
                   .GetValueOrDefault <T>());
        }
        internal virtual ArgumentConversionResult Convert(
            IArgument argument)
        {
            var parentResult = Parent;

            if (ShouldCheckArity() &&
                ArgumentArity.Validate(parentResult,
                                       argument,
                                       argument.Arity.MinimumNumberOfValues,
                                       argument.Arity.MaximumNumberOfValues) is FailedArgumentConversionResult failedResult)
            {
                return(failedResult);
            }

            if (argument is Argument arg)
            {
                if (parentResult !.UseDefaultValueFor(argument))
                {
                    var argumentResult = new ArgumentResult(arg, Parent);

                    var defaultValue = arg.GetDefaultValue(argumentResult);

                    if (string.IsNullOrEmpty(argumentResult.ErrorMessage))
                    {
                        return(ArgumentConversionResult.Success(
                                   argument,
                                   defaultValue));
                    }
                    else
                    {
                        return(ArgumentConversionResult.Failure(
                                   argument,
                                   argumentResult.ErrorMessage !));
                    }
                }

                if (arg.ConvertArguments != null)
                {
                    if (_conversionResult != null)
                    {
                        return(_conversionResult);
                    }

                    var success = arg.ConvertArguments(this, out var value);

                    if (value is ArgumentConversionResult conversionResult)
                    {
                        return(conversionResult);
                    }

                    if (success)
                    {
                        return(ArgumentConversionResult.Success(argument, value));
                    }

                    return(ArgumentConversionResult.Failure(
                               argument,
                               ErrorMessage ?? $"Invalid: {parentResult.Token()} {string.Join(" ", Tokens.Select(t => t.Value))}"));
                }
            }

            switch (argument.Arity.MaximumNumberOfValues)
            {
            case 1:
                return(ArgumentConversionResult.Success(
                           argument,
                           Tokens.Select(t => t.Value).SingleOrDefault()));

            default:
                return(ArgumentConversionResult.Success(
                           argument,
                           Tokens.Select(t => t.Value).ToArray()));
            }

            bool ShouldCheckArity() =>
            !(parentResult is OptionResult optionResult &&
              optionResult.IsImplicit);
        }
        private static void Diagram(
            this StringBuilder builder,
            SymbolResult symbolResult,
            ParseResult parseResult)
        {
            if (parseResult.Errors.Any(e => e.SymbolResult == symbolResult))
            {
                builder.Append("!");
            }


            switch (symbolResult)
            {
            case ArgumentResult argumentResult:
            {
                var includeArgumentName =
                    argumentResult.Argument.FirstParent !.Symbol is Command command &&
                    command.Arguments.Count > 1;

                if (includeArgumentName)
                {
                    builder.Append("[ ");
                    builder.Append(argumentResult.Argument.Name);
                    builder.Append(" ");
                }

                if (argumentResult.Argument.Arity.MaximumNumberOfValues > 0)
                {
                    ArgumentConversionResult conversionResult = argumentResult.GetArgumentConversionResult();
                    switch (conversionResult.Result)
                    {
                    case ArgumentConversionResultType.NoArgument:
                        break;

                    case ArgumentConversionResultType.Successful:
                        switch (conversionResult.Value)
                        {
                        case string s:
                            builder.Append($"<{s}>");
                            break;

                        case IEnumerable items:
                            builder.Append("<");
                            builder.Append(
                                string.Join("> <",
                                            items.Cast <object>().ToArray()));
                            builder.Append(">");
                            break;

                        default:
                            builder.Append("<");
                            builder.Append(conversionResult.Value);
                            builder.Append(">");
                            break;
                        }

                        break;

                    default:         // failures
                        builder.Append("<");
                        builder.Append(string.Join("> <", symbolResult.Tokens.Select(t => t.Value)));
                        builder.Append(">");

                        break;
                    }
                }

                if (includeArgumentName)
                {
                    builder.Append(" ]");
                }

                break;
            }

            default:
            {
                if (symbolResult is OptionResult {
                        IsImplicit : true
                    })
                {
                    builder.Append("*");
                }

                builder.Append("[ ");
                builder.Append(symbolResult.Token().Value);

                for (var i = 0; i < symbolResult.Children.Count; i++)
                {
                    var child = symbolResult.Children[i];

                    if (child is ArgumentResult arg &&
                        (arg.Argument.ValueType == typeof(bool) ||
                         arg.Argument.Arity.MaximumNumberOfValues == 0))
                    {
                        continue;
                    }

                    builder.Append(" ");

                    builder.Diagram(child, parseResult);
                }

                builder.Append(" ]");
                break;
            }