internal static IEnumerable <SymbolResult> AllSymbolResults(this SymbolResult symbolResult) { if (symbolResult == null) { throw new ArgumentNullException(nameof(symbolResult)); } yield return(symbolResult); foreach (var item in symbolResult .Children .FlattenBreadthFirst(o => o.Children)) { yield return(item); } }
public static T GetValueOrDefault <T>(this SymbolResult symbolResult) { ArgumentResult result = symbolResult.GetValueAs(typeof(T)); switch (result) { case SuccessfulArgumentResult successful: return((T)successful.Value); case FailedArgumentResult failed: throw new InvalidOperationException(failed.ErrorMessage); case NoArgumentResult _: default: return(default); } }
internal static FailedArgumentConversionArityResult Validate( SymbolResult symbolResult, IArgument argument, int minimumNumberOfValues, int maximumNumberOfValues) { var argumentResult = symbolResult.Children.ResultFor(argument); var tokenCount = argumentResult?.Tokens.Count ?? 0; if (tokenCount < minimumNumberOfValues) { if (symbolResult.UseDefaultValueFor(argument)) { return(null); } return(new MissingArgumentConversionResult( argument, symbolResult.ValidationMessages.RequiredArgumentMissing(symbolResult))); } if (tokenCount > maximumNumberOfValues) { if (maximumNumberOfValues == 1) { return(new TooManyArgumentsConversionResult( argument, symbolResult.ValidationMessages.ExpectsOneArgument(symbolResult))); } else { return(new TooManyArgumentsConversionResult( argument, symbolResult.ValidationMessages.ExpectsFewerArguments( symbolResult.Token, tokenCount, maximumNumberOfValues))); } } return(null); }
internal static ArgumentConversionResult?Validate( SymbolResult symbolResult, Argument argument, int minimumNumberOfValues, int maximumNumberOfValues) { var argumentResult = symbolResult switch { ArgumentResult a => a, _ => symbolResult.Root !.FindResultFor(argument) }; var tokenCount = argumentResult?.Tokens.Count ?? 0; if (tokenCount < minimumNumberOfValues) { if (symbolResult.UseDefaultValueFor(argument)) { return(null); } return(ArgumentConversionResult.Failure( argument, symbolResult.LocalizationResources.RequiredArgumentMissing(symbolResult), ArgumentConversionResultType.FailedMissingArgument)); } if (tokenCount > maximumNumberOfValues) { if (symbolResult is OptionResult optionResult) { if (!optionResult.Option.AllowMultipleArgumentsPerToken) { return(ArgumentConversionResult.Failure( argument, symbolResult !.LocalizationResources.ExpectsOneArgument(symbolResult), ArgumentConversionResultType.FailedTooManyArguments)); } } } return(null); }
internal void AddToSymbolMap(SymbolResult result) { switch (result) { case ArgumentResult argumentResult: _allArgumentResults.Add(argumentResult.Argument, argumentResult); break; case CommandResult commandResult: _allCommandResults.Add(commandResult.Command, commandResult); break; case OptionResult optionResult: _allOptionResults.Add(optionResult.Option, optionResult); break; default: throw new ArgumentException($"Unsupported {nameof(SymbolResult)} type: {result.GetType()}"); } }
internal static FailedArgumentConversionArityResult?Validate( SymbolResult symbolResult, IArgument argument, int minimumNumberOfValues, int maximumNumberOfValues ) { var argumentResult = symbolResult switch { ArgumentResult a => a, _ => symbolResult.Root !.FindResultFor(argument) }; var tokenCount = argumentResult?.Tokens.Count ?? 0; if (tokenCount < minimumNumberOfValues) { if (symbolResult !.UseDefaultValueFor(argument)) { return(null); } return(new MissingArgumentConversionResult( argument, symbolResult.ValidationMessages.RequiredArgumentMissing(symbolResult) )); } if (tokenCount > maximumNumberOfValues) { return(new TooManyArgumentsConversionResult( argument, symbolResult !.ValidationMessages.ExpectsOneArgument(symbolResult) )); } return(null); }
public bool TryGetValueForOption(IValueDescriptor valueDescriptor, out object value) { var children = Children .Where(o => valueDescriptor.ValueName.IsMatch(o.Symbol)) .ToArray(); SymbolResult symbolResult = null; if (children.Length > 1) { throw new ArgumentException($"Ambiguous match while trying to bind parameter {valueDescriptor.ValueName} among: {string.Join(",", children.Select(o => o.Name))}"); } if (children.Length == 1) { symbolResult = children[0]; } if (symbolResult is OptionResult optionResult && optionResult.GetValueAs(valueDescriptor.Type) is SuccessfulArgumentResult successful) { value = successful.Value; return(true); }
internal static FailedArgumentArityResult Validate( SymbolResult symbolResult, int minimumNumberOfArguments, int maximumNumberOfArguments) { if (symbolResult.Arguments.Count < minimumNumberOfArguments) { return(new FailedArgumentArityResult(symbolResult.ValidationMessages.RequiredArgumentMissing(symbolResult))); } if (symbolResult.Arguments.Count > maximumNumberOfArguments) { if (maximumNumberOfArguments == 1) { return(new FailedArgumentArityResult(symbolResult.ValidationMessages.ExpectsOneArgument(symbolResult))); } else { return(new FailedArgumentArityResult(symbolResult.ValidationMessages.ExpectsFewerArguments(symbolResult, maximumNumberOfArguments))); } } return(null); }
public virtual string ExpectsOneArgument(SymbolResult symbolResult) => symbolResult is CommandResult ? $"Command '{symbolResult.Token.Value}' expects a single argument but {symbolResult.Tokens.Count} were provided." : $"Option '{symbolResult.Token.Value}' expects a single argument but {symbolResult.Tokens.Count} were provided.";
public virtual string ExpectsFewerArguments(SymbolResult symbolResult, int maximumNumberOfArguments) => symbolResult is CommandResult ? $"Command '{symbolResult.Token}' expects no more than {maximumNumberOfArguments} arguments, but {symbolResult.Arguments.Count} were provided." : $"Option '{symbolResult.Token}' expects no more than {maximumNumberOfArguments} arguments, but {symbolResult.Arguments.Count} were provided.";
private static void Diagram( this StringBuilder builder, SymbolResult symbolResult, ParseResult parseResult) { if (parseResult.Errors.Any(e => e.SymbolResult == symbolResult)) { builder.Append("!"); } if (symbolResult is OptionResult option && option.IsImplicit) { builder.Append("*"); } builder.Append("[ "); builder.Append(symbolResult.Token.Value); foreach (var child in symbolResult.Children) { builder.Append(" "); builder.Diagram(child, parseResult); } if (symbolResult.Tokens.Count > 0) { foreach (var arg in symbolResult.Tokens) { builder.Append(" <"); builder.Append(arg.Value); builder.Append(">"); } } else { foreach (var result in symbolResult.ArgumentResults) { if (result is SuccessfulArgumentResult successfulArgumentResult) { var value = successfulArgumentResult.Value; switch (value) { case null: case IReadOnlyCollection <string> a when a.Count == 0: break; default: builder.Append(" <"); builder.Append(value); builder.Append(">"); break; } } } } builder.Append(" ]"); }
public static T GetValueOrDefault <T>(this SymbolResult symbolResult) { if (symbolResult == null) { return(default);
public virtual ParseResult Parse( IReadOnlyCollection <string> arguments, string rawInput = null) { var rawTokens = arguments; // allow a more user-friendly name for callers of Parse var lexResult = NormalizeRootCommand(rawTokens).Lex(Configuration); var directives = new List <string>(); var unparsedTokens = new Queue <Token>(lexResult.Tokens); var allSymbolResults = new List <SymbolResult>(); var errors = new List <ParseError>(lexResult.Errors); var unmatchedTokens = new List <Token>(); CommandResult rootCommand = null; CommandResult innermostCommand = null; IList <IOption> optionQueue = GatherOptions(Configuration.Symbols); while (unparsedTokens.Any()) { var token = unparsedTokens.Dequeue(); if (token.Type == TokenType.EndOfArguments) { // stop parsing further tokens break; } if (token.Type != TokenType.Argument) { var symbol = Configuration.Symbols .SingleOrDefault(o => o.HasAlias(token.Value)); if (symbol != null) { var result = allSymbolResults .LastOrDefault(o => o.HasAlias(token.Value)); if (result == null) { result = SymbolResult.Create(symbol, token.Value, validationMessages: Configuration.ValidationMessages); rootCommand = (CommandResult)result; } allSymbolResults.Add(result); continue; } } if (token.Type == TokenType.Directive) { var withoutBrackets = token.Value.Substring(1, token.Value.Length - 2); directives.Add(withoutBrackets); continue; } var added = false; foreach (var topLevelSymbol in Enumerable.Reverse(allSymbolResults)) { var symbolForToken = topLevelSymbol.TryTakeToken(token); if (symbolForToken != null) { allSymbolResults.Add(symbolForToken); added = true; if (symbolForToken is CommandResult command) { ProcessImplicitTokens(); innermostCommand = command; } if (token.Type == TokenType.Option) { var existing = optionQueue.FirstOrDefault(option => option.Name == symbolForToken.Name); if (existing != null) { // we've used this option - don't use it again optionQueue.Remove(existing); } } break; } if (token.Type == TokenType.Argument && topLevelSymbol.Symbol is ICommand) { break; } } if (!added) { unmatchedTokens.Add(token); } } ProcessImplicitTokens(); if (Configuration.RootCommand.TreatUnmatchedTokensAsErrors) { errors.AddRange( unmatchedTokens.Select(token => new ParseError(Configuration.ValidationMessages.UnrecognizedCommandOrArgument(token.Value)))); } return(new ParseResult( rootCommand, innermostCommand ?? rootCommand, directives, rawTokens, unparsedTokens.Select(t => t.Value).ToArray(), unmatchedTokens.Select(t => t.Value).ToArray(), errors, rawInput)); void ProcessImplicitTokens() { if (!Configuration.EnablePositionalOptions) { return; } var currentCommand = innermostCommand ?? rootCommand; if (currentCommand == null) { return; } Token[] tokensToAttemptByPosition = Enumerable.Reverse(unmatchedTokens) .TakeWhile(x => x.Type != TokenType.Command) .Reverse() .ToArray(); foreach (Token token in tokensToAttemptByPosition) { var option = optionQueue.FirstOrDefault(); if (option != null) { var newToken = new Token(option.RawAliases.First(), TokenType.Option); var optionResult = currentCommand.TryTakeToken(newToken); var optionArgument = optionResult?.TryTakeToken(token); if (optionArgument != null) { optionQueue.RemoveAt(0); allSymbolResults.Add(optionResult); if (optionResult != optionArgument) { allSymbolResults.Add(optionArgument); } unmatchedTokens.Remove(token); } else if (optionResult != null) { currentCommand.Children.Remove(optionResult); } } } } }
public virtual string NoArgumentsAllowed(SymbolResult symbolResult) => $"Arguments not allowed for option: {symbolResult.Token}";
public virtual string NoArgumentProvided(SymbolResult symbolResult) => symbolResult is CommandResult ? $"No argument was provided for Command '{symbolResult.Token.Value}'." : $"No argument was provided for Option '{symbolResult.Token.Value}'.";
public virtual string RequiredArgumentMissing(SymbolResult symbolResult) => symbolResult is CommandResult ? $"Required argument missing for command: {symbolResult.Token.Value}" : $"Required argument missing for option: {symbolResult.Token.Value}";
public virtual string ExpectsOneArgument(SymbolResult symbolResult) => symbolResult is CommandResult ? GetResourceString(Properties.Resources.CommandExpectsOneArgument, symbolResult.Token().Value, symbolResult.Tokens.Count) : GetResourceString(Properties.Resources.OptionExpectsOneArgument, symbolResult.Token().Value, symbolResult.Tokens.Count);
public static object GetValueOrDefault(this SymbolResult symbolResult) { return(symbolResult.GetValueOrDefault <object>()); }
public virtual string NoArgumentProvided(SymbolResult symbolResult) => symbolResult is CommandResult ? GetResourceString(Properties.Resources.CommandNoArgumentProvided, symbolResult.Token().Value) : GetResourceString(Properties.Resources.OptionNoArgumentProvided, symbolResult.Token().Value);
private static void Diagram( this StringBuilder builder, SymbolResult symbolResult, ParseResult parseResult) { if (parseResult.Errors.Any(e => e.SymbolResult == symbolResult)) { builder.Append("!"); } if (symbolResult is OptionResult optionResult && optionResult.IsImplicit) { builder.Append("*"); } if (symbolResult is ArgumentResult argumentResult) { var includeArgumentName = argumentResult.Argument is Argument argument && argument.Parents[0] is ICommand command && command.Name != argument.Name; if (includeArgumentName) { builder.Append("[ "); builder.Append(argumentResult.Argument.Name); builder.Append(" "); } switch (symbolResult.ArgumentConversionResult) { case SuccessfulArgumentConversionResult successful: switch (successful.Value) { case null: case IReadOnlyCollection <string> a when a.Count == 0: break; case IEnumerable <string> args: builder.Append("<"); builder.Append(string.Join("> <", args)); builder.Append(">"); break; default: builder.Append("<"); builder.Append(successful.Value); builder.Append(">"); break; } break; case FailedArgumentConversionResult _: builder.Append("<"); builder.Append(string.Join("> <", symbolResult.Tokens.Select(t => t.Value))); builder.Append(">"); break; } if (includeArgumentName) { builder.Append(" ]"); } } else { builder.Append("[ "); builder.Append(symbolResult.Token.Value); foreach (var child in symbolResult.Children) { builder.Append(" "); builder.Diagram(child, parseResult); } builder.Append(" ]"); } }
public virtual string RequiredArgumentMissing(SymbolResult symbolResult) => symbolResult is CommandResult ? GetResourceString(Properties.Resources.CommandRequiredArgumentMissing, symbolResult.Token().Value) : GetResourceString(Properties.Resources.OptionRequiredArgumentMissing, symbolResult.Token().Value);