public ParameterArgumentDef(
            ParameterInfo parameterInfo,
            CommandNodeType commandNodeType,
            AppConfig appConfig,
            object?[] parameterValues)
        {
            if (parameterValues == null)
            {
                throw new ArgumentNullException(nameof(parameterValues));
            }

            _parameterInfo  = parameterInfo ?? throw new ArgumentNullException(nameof(parameterInfo));
            CommandNodeType = commandNodeType;
            Name            = parameterInfo.BuildName(commandNodeType, appConfig);

            IsOptional = _parameterInfo.IsOptional || _parameterInfo.IsNullableParameter();

            BooleanMode = this.GetBooleanMode(appConfig.AppSettings.Arguments.BooleanMode);
            Split       = this.GetSplitChar();

            ValueProxy = new ValueProxy(
                () => parameterValues[parameterInfo.Position],

                value => parameterValues[parameterInfo.Position] = value
                );
            Arity = ArgumentArity.Default(this);
        }
Example #2
0
        private void ValidateCommand(CommandResult commandResult)
        {
            foreach (var a in commandResult
                     .Command
                     .Arguments)
            {
                if (a is Argument argument)
                {
                    var arityFailure = ArgumentArity.Validate(
                        commandResult,
                        a,
                        a.Arity.MinimumNumberOfValues,
                        a.Arity.MaximumNumberOfValues);

                    if (arityFailure != null)
                    {
                        _errors.Add(
                            new ParseError(arityFailure.ErrorMessage, commandResult));
                    }

                    foreach (var validator in argument.SymbolValidators)
                    {
                        var errorMessage = validator(commandResult);

                        if (!string.IsNullOrWhiteSpace(errorMessage))
                        {
                            _errors.Add(
                                new ParseError(errorMessage, commandResult));
                        }
                    }
                }
            }
        }
        public void DefaultNullableBool(BooleanMode booleanMode, bool isOptional, bool hasDefault, int expectedMin, int expectedMax)
        {
            var actual   = ArgumentArity.Default(typeof(bool?), isOptional, hasDefault, booleanMode);
            var expected = new ArgumentArity(expectedMin, expectedMax);

            actual.Should().Be(expected);
        }
        public PropertyArgumentDef(
            PropertyInfo propertyInfo,
            CommandNodeType commandNodeType,
            AppConfig appConfig,
            object modelInstance)
        {
            if (modelInstance == null)
            {
                throw new ArgumentNullException(nameof(modelInstance));
            }

            _propertyInfo = propertyInfo ?? throw new ArgumentNullException(nameof(propertyInfo));

            CommandNodeType = commandNodeType;
            Name            = propertyInfo.BuildName(commandNodeType, appConfig);
            IsOptional      = propertyInfo.IsNullableProperty();

            BooleanMode = this.GetBooleanMode(appConfig.AppSettings.Arguments.BooleanMode);
            Split       = this.GetSplitChar();

            ValueProxy = new ValueProxy(
                () => _propertyInfo.GetValue(modelInstance),

                value => _propertyInfo.SetValue(modelInstance, value)
                );
            DefaultValue    = propertyInfo.GetValue(modelInstance);
            HasDefaultValue = propertyInfo.PropertyType.IsClass
                ? !DefaultValue.IsNullValue()
                : !DefaultValue?.IsDefaultFor(propertyInfo.PropertyType) ?? false;
            Arity = ArgumentArity.Default(this);
        }
        public void Default(Type type, bool isOptional, bool hasDefault, int expectedMin, int expectedMax)
        {
            var actual   = ArgumentArity.Default(type, isOptional, hasDefault, BooleanMode.Explicit);
            var expected = new ArgumentArity(expectedMin, expectedMax);

            actual.Should().Be(expected);
        }
Example #6
0
        private void ValidateArgument(ArgumentResult argumentResult)
        {
            var arityFailure = ArgumentArity.Validate(argumentResult);

            if (arityFailure != null)
            {
                _errors.Add(new ParseError(arityFailure.ErrorMessage));
                return;
            }

            if (argumentResult.Argument is Argument argument)
            {
                var parseError = argumentResult.Parent.UnrecognizedArgumentError(argument) ??
                                 argumentResult.Parent.CustomError(argument);

                if (parseError != null)
                {
                    _errors.Add(parseError);
                    return;
                }
            }

            if (argumentResult.ArgumentConversionResult is FailedArgumentConversionResult failed)
            {
                _errors.Add(
                    new ParseError(
                        failed.ErrorMessage,
                        argumentResult));
            }
        }
 private IEnumerable <Option> GenerateTestOptions(int count, ArgumentArity arity)
 => Enumerable.Range(0, count)
 .Select(i => new Option($"-option{i}", arity: arity)
 {
     Description = $"Description for -option {i} ...."
 }
         );
        public void DefaultNullableBool(BooleanMode booleanMode, bool hasDefaultValue, int expectedMin, int expectedMax)
        {
            var actual   = ArgumentArity.Default(typeof(bool?), hasDefaultValue, booleanMode);
            var expected = new ArgumentArity(expectedMin, expectedMax);

            expected.Should().Be(actual);
        }
        public void Default(Type type, bool hasDefaultValue, int expectedMin, int expectedMax)
        {
            var actual   = ArgumentArity.Default(type, hasDefaultValue, BooleanMode.Explicit);
            var expected = new ArgumentArity(expectedMin, expectedMax);

            expected.Should().Be(actual);
        }
Example #10
0
    public void Verify_option_configuration(string alias, ArgumentArity arity, int elementIndex)
    {
        var computeHistoryCommand = new ComputeHistoryCommand();
        var option = computeHistoryCommand.Options.ElementAt(elementIndex);

        option.Name.Should().Be(alias);
        option.Arity.Should().BeEquivalentTo(arity);
    }
Example #11
0
    public void Verify_argument_configuration(string alias, ArgumentArity arity, int elementIndex)
    {
        var checkoutHistoryCommand = new CheckoutHistoryCommand();
        var argument = checkoutHistoryCommand.Arguments.ElementAt(elementIndex);

        argument.Name.Should().Be(alias);
        argument.Arity.Should().BeEquivalentTo(arity);
    }
Example #12
0
 internal static Option <string[]> CreateAddSourceOption()
 {
     return(new(new[] { "--add-source", "--nuget-source" })
     {
         Arity = new ArgumentArity(1, 99),
         Description = SymbolStrings.Option_AddSource,
         AllowMultipleArgumentsPerToken = true,
     });
Example #13
0
        private static IArgument BuildArgument(IArgumentDef argumentDef,
                                               Command parent,
                                               AppConfig appConfig,
                                               TypeInfo typeInfo,
                                               bool isInterceptorOption)
        {
            var defaultValue = argumentDef.HasDefaultValue ? argumentDef.DefaultValue : null;

            if (argumentDef.CommandNodeType == CommandNodeType.Operand)
            {
                var operandAttr = argumentDef.CustomAttributes.GetCustomAttribute <OperandAttribute>()
                                  ?? (INameAndDescription)argumentDef.CustomAttributes.GetCustomAttribute <ArgumentAttribute>();
                return(new Operand(
                           argumentDef.Name,
                           parent,
                           typeInfo,
                           ArgumentArity.Default(argumentDef.Type, argumentDef.HasDefaultValue, BooleanMode.Explicit),
                           argumentDef.SourcePath,
                           customAttributes: argumentDef.CustomAttributes,
                           argumentDef.ValueProxy)
                {
                    Description = operandAttr?.Description,
                    DefaultValue = defaultValue
                });
            }

            if (argumentDef.CommandNodeType == CommandNodeType.Option)
            {
                var optionAttr    = argumentDef.CustomAttributes.GetCustomAttribute <OptionAttribute>();
                var booleanMode   = GetOptionBooleanMode(argumentDef, appConfig.AppSettings.BooleanMode, optionAttr);
                var argumentArity = ArgumentArity.Default(argumentDef.Type, argumentDef.HasDefaultValue, booleanMode);

                var assignOnlyToExecutableSubcommands = optionAttr?.AssignToExecutableSubcommands ?? false;
                isInterceptorOption = isInterceptorOption && !assignOnlyToExecutableSubcommands;

                var longName = optionAttr?.ShortName != null
                    ? optionAttr?.LongName
                    : (optionAttr?.LongName ?? argumentDef.Name);
                return(new Option(
                           longName,
                           ParseShortName(argumentDef, optionAttr?.ShortName),
                           parent,
                           typeInfo,
                           argumentArity,
                           definitionSource: argumentDef.SourcePath,
                           customAttributes: argumentDef.CustomAttributes,
                           isInterceptorOption: isInterceptorOption,
                           assignToExecutableSubcommands: assignOnlyToExecutableSubcommands,
                           valueProxy: argumentDef.ValueProxy)
                {
                    Description = optionAttr?.Description,
                    DefaultValue = defaultValue
                });
            }

            throw new ArgumentOutOfRangeException($"Unknown argument type: {argumentDef.CommandNodeType}");
        }
Example #14
0
    public static void VerifyAlias <T>(string alias, ArgumentArity arity, bool allowMultipleArgumentsPerToken)
        where T : Command, new()
    {
        var command = new T();
        var option  = command.Options.FirstOrDefault(x => x.Aliases.Contains(alias));

        option.Should().NotBeNull();
        option !.AllowMultipleArgumentsPerToken.Should().Be(allowMultipleArgumentsPerToken);
        option.Arity.Should().BeEquivalentTo(arity);
    }
Example #15
0
        protected override void Stop(SyntaxNode node)
        {
            ValidateCommandHandler(_innermostCommandResult);

            foreach (var commandResult in _innermostCommandResult.RecurseWhileNotNull(c => c.ParentCommandResult))
            {
                foreach (var symbol in commandResult.Command.Children)
                {
                    PopulateDefaultValues(commandResult, symbol);
                }

                ValidateCommand(commandResult);

                foreach (var result in commandResult.Children)
                {
                    switch (result)
                    {
                    case ArgumentResult argumentResult:

                        ValidateArgument(argumentResult);

                        break;

                    case OptionResult optionResult:

                        var argument = optionResult.Option.Argument;

                        var arityFailure = ArgumentArity.Validate(
                            optionResult,
                            argument,
                            argument.Arity.MinimumNumberOfValues,
                            argument.Arity.MaximumNumberOfValues);

                        if (arityFailure != null)
                        {
                            _errors.Add(
                                new ParseError(arityFailure.ErrorMessage, optionResult));
                        }

                        var results = optionResult.Children
                                      .OfType <ArgumentResult>()
                                      .ToArray();

                        foreach (var a in results)
                        {
                            ValidateArgument(a);
                        }

                        break;
                    }
                }
            }
        }
Example #16
0
        private void ValidateCommandResult()
        {
            if (_innermostCommandResult !.Command is Command command)
            {
                for (var i = 0; i < command.Validators.Count; i++)
                {
                    var validator    = command.Validators[i];
                    var errorMessage = validator(_innermostCommandResult);

                    if (!string.IsNullOrWhiteSpace(errorMessage))
                    {
                        _errors.Add(
                            new ParseError(errorMessage !, _innermostCommandResult));
                    }
                }
            }

            foreach (var option in _innermostCommandResult
                     .Command
                     .Options)
            {
                if (option is Option o &&
                    o.IsRequired &&
                    _rootCommandResult !.FindResultFor(o) is null)
                {
                    _errors.Add(
                        new ParseError($"Option '{o.Aliases.First()}' is required.",
                                       _innermostCommandResult));
                }
            }

            foreach (var symbol in _innermostCommandResult
                     .Command
                     .Arguments)
            {
                var arityFailure = ArgumentArity.Validate(
                    _innermostCommandResult,
                    symbol,
                    symbol.Arity.MinimumNumberOfValues,
                    symbol.Arity.MaximumNumberOfValues);

                if (arityFailure != null)
                {
                    _errors.Add(
                        new ParseError(arityFailure.ErrorMessage !, _innermostCommandResult));
                }
            }
        }
Example #17
0
        private void ValidateCommandResult(CommandResult commandResult)
        {
            if (commandResult.Command is Command command)
            {
                foreach (var validator in command.Validators)
                {
                    var errorMessage = validator(commandResult);

                    if (!string.IsNullOrWhiteSpace(errorMessage))
                    {
                        _errors.Add(
                            new ParseError(errorMessage, commandResult));
                    }
                }
            }

            foreach (var option in commandResult
                     .Command
                     .Options)
            {
                if (option is Option o &&
                    o.Required &&
                    _rootCommandResult.FindResultFor(o) == null)
                {
                    _errors.Add(
                        new ParseError($"Option '{o.RawAliases.First()}' is required.",
                                       commandResult));
                }
            }

            foreach (var symbol in commandResult
                     .Command
                     .Arguments)
            {
                var arityFailure = ArgumentArity.Validate(
                    commandResult,
                    symbol,
                    symbol.Arity.MinimumNumberOfValues,
                    symbol.Arity.MaximumNumberOfValues);

                if (arityFailure != null)
                {
                    _errors.Add(
                        new ParseError(arityFailure.ErrorMessage, commandResult));
                }
            }
        }
Example #18
0
        private void ValidateOptionResult(OptionResult optionResult)
        {
            var argument = optionResult.Option.Argument;

            var arityFailure = ArgumentArity.Validate(
                optionResult,
                argument,
                argument.Arity.MinimumNumberOfValues,
                argument.Arity.MaximumNumberOfValues);

            if (arityFailure != null)
            {
                _errors.Add(
                    new ParseError(arityFailure.ErrorMessage !, optionResult));
            }

            if (optionResult.Option is Option option)
            {
                for (var i = 0; i < option.Validators.Count; i++)
                {
                    var validate = option.Validators[i];
                    var message  = validate(optionResult);

                    if (!string.IsNullOrWhiteSpace(message))
                    {
                        _errors.Add(new ParseError(message !, optionResult));
                    }
                }
            }

            for (var i = 0; i < optionResult.Children.Count; i++)
            {
                var result = optionResult.Children[i];
                if (result is ArgumentResult argumentResult)
                {
                    ValidateArgumentResult(argumentResult);
                }
            }
        }
        private void ValidateOptionResult(OptionResult optionResult)
        {
            var argument = optionResult.Option.Argument;

            var arityFailure = ArgumentArity.Validate(
                optionResult,
                argument,
                argument.Arity.MinimumNumberOfValues,
                argument.Arity.MaximumNumberOfValues);

            if (arityFailure != null)
            {
                _errors.Add(
                    new ParseError(arityFailure.ErrorMessage !, optionResult));
            }

            if (optionResult.Option is Option option)
            {
                foreach (var validate in option.Validators)
                {
                    var message = validate(optionResult);

                    if (!string.IsNullOrWhiteSpace(message))
                    {
                        _errors.Add(new ParseError(message !, optionResult));
                    }
                }
            }

            foreach (var argumentResult in optionResult
                     .Children
                     .OfType <ArgumentResult>())
            {
                ValidateArgumentResult(argumentResult);
            }
        }
Example #20
0
 public void VerifyOptionConfigurations(string alias, ArgumentArity arity, bool allowsMultiples) =>
 TestHelpers.VerifyAlias <ScanCommand>(alias, arity, allowsMultiples);
Example #21
0
        public static Command RootCommand()
        {
            // For some reason, arity caps at 255 by default
            ArgumentArity arbitraryArity = new ArgumentArity(0, 100000);

            return(new Command("Crossgen2Compilation")
            {
                new Argument <FileInfo[]>()
                {
                    Name = "input-file-paths",
                    Description = SR.InputFilesToCompile,
                    Arity = arbitraryArity,
                },
                new Option(new[] { "--unrooted-input-file-paths", "-u" }, SR.UnrootedInputFilesToCompile)
                {
                    Argument = new Argument <FileInfo[]>()
                    {
                        Arity = arbitraryArity
                    }
                },
                new Option(new[] { "--reference", "-r" }, SR.ReferenceFiles)
                {
                    Argument = new Argument <string[]>()
                    {
                        Arity = arbitraryArity
                    }
                },
                new Option(new[] { "--instruction-set" }, SR.InstructionSets)
                {
                    Argument = new Argument <string>()
                },
                new Option(new[] { "--mibc", "-m" }, SR.MibcFiles)
                {
                    Argument = new Argument <string[]>()
                    {
                        Arity = arbitraryArity
                    }
                },
                new Option(new[] { "--outputfilepath", "--out", "-o" }, SR.OutputFilePath)
                {
                    Argument = new Argument <FileInfo>()
                },
                new Option(new[] { "--optimize", "-O" }, SR.EnableOptimizationsOption)
                {
                    Argument = new Argument <bool>()
                },
                new Option(new[] { "--optimize-space", "--Os" }, SR.OptimizeSpaceOption)
                {
                    Argument = new Argument <bool>()
                },
                new Option(new[] { "--optimize-time", "--Ot" }, SR.OptimizeSpeedOption),
                new Option(new[] { "--inputbubble" }, SR.InputBubbleOption),
                new Option(new[] { "--composite" }, SR.CompositeBuildMode),
                new Option(new[] { "--tuning" }, SR.TuningImageOption)
                {
                    Argument = new Argument <bool>()
                },
                new Option(new[] { "--partial" }, SR.PartialImageOption)
                {
                    Argument = new Argument <bool>()
                },
                new Option(new[] { "--compilebubblegenerics" }, SR.BubbleGenericsOption)
                {
                    Argument = new Argument <bool>()
                },
                new Option(new[] { "--dgml-log-file-name", "--dmgllog" }, SR.SaveDependencyLogOption)
                {
                    Argument = new Argument <FileInfo>()
                },
                new Option(new[] { "--generate-full-dmgl-log", "--fulllog" }, SR.SaveDetailedLogOption)
                {
                    Argument = new Argument <bool>()
                },
                new Option(new[] { "--verbose" }, SR.VerboseLoggingOption)
                {
                    Argument = new Argument <bool>()
                },
                new Option(new[] { "--systemmodule" }, SR.SystemModuleOverrideOption)
                {
                    Argument = new Argument <string>()
                },
                new Option(new[] { "--waitfordebugger" }, SR.WaitForDebuggerOption)
                {
                    Argument = new Argument <bool>()
                },
                new Option(new[] { "--codegen-options", "--codegenopt" }, SR.CodeGenOptions)
                {
                    Argument = new Argument <string[]>()
                    {
                        Arity = arbitraryArity
                    }
                },
                new Option(new[] { "--resilient" }, SR.ResilientOption)
                {
                    Argument = new Argument <bool>()
                },
                new Option(new[] { "--targetarch" }, SR.TargetArchOption)
                {
                    Argument = new Argument <string>()
                },
                new Option(new[] { "--targetos" }, SR.TargetOSOption)
                {
                    Argument = new Argument <string>()
                },
                new Option(new[] { "--jitpath" }, SR.JitPathOption)
                {
                    Argument = new Argument <FileInfo>()
                },
                new Option(new[] { "--singlemethodtypename" }, SR.SingleMethodTypeName)
                {
                    Argument = new Argument <string>()
                },
                new Option(new[] { "--singlemethodname" }, SR.SingleMethodMethodName)
                {
                    Argument = new Argument <string>()
                },
                new Option(new[] { "--singlemethodgenericarg" }, SR.SingleMethodGenericArgs)
                {
                    // We don't need to override arity here as 255 is the maximum number of generic arguments
                    Argument = new Argument <string[]>()
                },
                new Option(new[] { "--parallelism" }, SR.ParalellismOption)
                {
                    Argument = new Argument <int>(() => Environment.ProcessorCount)
                },
                new Option(new[] { "--map" }, SR.MapFileOption)
                {
                    Argument = new Argument <bool>()
                },
            });
        }
 public void DefaultBooleanModeCannotBeUnknown()
 {
     Assert.Throws <ArgumentException>(
         () => ArgumentArity.Default(typeof(bool), NoDefault, BooleanMode.Unknown))
     .Message.Should().Be("booleanMode cannot be Unknown");
 }
Example #23
0
        public Argument()
        {
            Arity = ArgumentArity.DefaultForType(typeof(T));

            ArgumentType = typeof(T);
        }
Example #24
0
        public static Command RootCommand()
        {
            // For some reason, arity caps at 255 by default
            ArgumentArity arbitraryArity = new ArgumentArity(0, 100000);

            return(new Command("Crossgen2Compilation")
            {
                new Argument <FileInfo[]>()
                {
                    Name = "input-file-paths",
                    Description = "Input file(s) to compile",
                    Arity = arbitraryArity,
                },
                new Option(new[] { "--reference", "-r" }, "Reference file(s) for compilation")
                {
                    Argument = new Argument <string[]>()
                    {
                        Arity = arbitraryArity
                    }
                },
                new Option(new[] { "--outputfilepath", "--out", "-o" }, "Output file path")
                {
                    Argument = new Argument <FileInfo>()
                },
                new Option(new[] { "--optimize", "-O" }, "Enable optimizations")
                {
                    Argument = new Argument <bool>()
                },
                new Option(new[] { "--optimize-space", "--Os" }, "Enable optimizations, favor code space")
                {
                    Argument = new Argument <bool>()
                },
                new Option(new[] { "--optimize-time", "--Ot" }, "Enable optimizations, favor code speed"),
                new Option(new[] { "--inputbubble" }, "True when the entire input forms a version bubble (default = per-assembly bubble)"),
                new Option(new[] { "--tuning" }, "Generate IBC tuning image")
                {
                    Argument = new Argument <bool>()
                },
                new Option(new[] { "--partial" }, "Generate partial image driven by profile")
                {
                    Argument = new Argument <bool>()
                },
                new Option(new[] { "--compilebubblegenerics" }, "Compile instantiations from reference modules used in the current module")
                {
                    Argument = new Argument <bool>()
                },
                new Option(new[] { "--dgml-log-file-name", "--dmgllog" }, "Save result of dependency analysis as DGML")
                {
                    Argument = new Argument <FileInfo>()
                },
                new Option(new[] { "--generate-full-dmgl-log", "--fulllog" }, "Save detailed log of dependency analysis")
                {
                    Argument = new Argument <bool>()
                },
                new Option(new[] { "--verbose" }, "Enable verbose logging")
                {
                    Argument = new Argument <bool>()
                },
                new Option(new[] { "--systemmodule" }, "System module name (default: System.Private.CoreLib)")
                {
                    Argument = new Argument <string>()
                },
                new Option(new[] { "--waitfordebugger" }, "Pause to give opportunity to attach debugger")
                {
                    Argument = new Argument <bool>()
                },
                new Option(new[] { "--codegen-options", "--codegenopt" }, "Define a codegen option")
                {
                    Argument = new Argument <string[]>()
                    {
                        Arity = arbitraryArity
                    }
                },
                new Option(new[] { "--resilient" }, "Disable behavior where unexpected compilation failures cause overall compilation failure")
                {
                    Argument = new Argument <bool>()
                },
                new Option(new[] { "--targetarch" }, "Target architecture for cross compilation")
                {
                    Argument = new Argument <string>()
                },
                new Option(new[] { "--targetos" }, "Target OS for cross compilation")
                {
                    Argument = new Argument <string>()
                },
                new Option(new[] { "--jitpath" }, "Path to JIT compiler library")
                {
                    Argument = new Argument <string>()
                },
                new Option(new[] { "--singlemethodtypename" }, "Single method compilation: name of the owning type")
                {
                    Argument = new Argument <string>()
                },
                new Option(new[] { "--singlemethodname" }, "Single method compilation: generic arguments to the method")
                {
                    Argument = new Argument <string>()
                },
                new Option(new[] { "--singlemethodgenericarg" }, "Single method compilation: generic arguments to the method")
                {
                    // We don't need to override arity here as 255 is the maximum number of generic arguments
                    Argument = new Argument <string[]>()
                },
                new Option(new[] { "--parallelism" }, "Maximum number of threads to use during compilation")
                {
                    Argument = new Argument <int>(() => Environment.ProcessorCount)
                },
                new Option(new[] { "--map" }, "Generate the map file")
                {
                    Argument = new Argument <bool>()
                },
            });
        }
Example #25
0
        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 (parentResult.UseDefaultValueFor(argument))
            {
                var defaultValueFor = parentResult.GetDefaultValueFor(argument);

                return(ArgumentConversionResult.Success(argument, defaultValueFor));
            }

            if (argument is Argument a &&
                a.ConvertArguments != null)
            {
                if (ConversionResult != null)
                {
                    return(ConversionResult);
                }

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

                if (value is ArgumentConversionResult conversionResult)
                {
                    return(conversionResult);
                }
                else if (success)
                {
                    return(ArgumentConversionResult.Success(argument, value));
                }
                else
                {
                    return(ArgumentConversionResult.Failure(argument, ErrorMessage ?? $"Invalid: {parentResult.Token()} {string.Join(" ", parentResult.Tokens.Select(t => t.Value))}"));
                }
            }

            switch (argument.Arity.MaximumNumberOfValues)
            {
            case 0:
                return(ArgumentConversionResult.Success(argument, null));

            case 1:
                return(ArgumentConversionResult.Success(argument, parentResult.Tokens.Select(t => t.Value).SingleOrDefault()));

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

            bool ShouldCheckArity()
            {
                return(!(parentResult is OptionResult optionResult &&
                         optionResult.IsImplicit));
            }
        }