private void ParseString( CommandTreeParserContext context, TokenStream stream, CommandTree node) { var token = stream.Expect(Token.Type.String); // Command? var command = node.Command.FindCommand(token.Value); if (command != null) { node.Next = ParseCommand(context, node.Command, node, stream); return; } // Current command has no arguments? if (!node.HasArguments()) { throw new CommandAppException($"Unknown child command '{token.Value}' of '{node.Command.Name}'."); } // Argument? var parameter = node.FindArgument(context.CurrentArgumentPosition); if (parameter == null) { throw new CommandAppException($"Could not match '{token.Value}' with an argument."); } node.Mapped.Add((parameter, stream.Consume(Token.Type.String).Value)); context.IncreaseArgumentPosition(); }
public static CommandTree GetRootCommand(this CommandTree node) { while (node.Parent != null) { node = node.Parent; } return(node); }
public static CommandTree GetLeafCommand(this CommandTree node) { while (node.Next != null) { node = node.Next; } return(node); }
private CommandTree ParseCommand( CommandTreeParserContext context, ICommandContainer current, CommandTree parent, TokenStream stream) { context.ResetArgumentPosition(); // Find the command. var commandToken = stream.Consume(Token.Type.String); var command = current.FindCommand(commandToken.Value); if (command == null) { throw new CommandAppException($"Unknown command '{commandToken.Value}'."); } var node = new CommandTree(parent, command); while (stream.Peek() != null) { var token = stream.Peek(); switch (token.TokenType) { case Token.Type.LongOption: // Long option ParseOption(context, stream, node, true); break; case Token.Type.ShortOption: // Short option ParseOption(context, stream, node, false); break; case Token.Type.String: // Command ParseString(context, stream, node); break; default: throw new InvalidOperationException("Unknown token type."); } } // Add unmapped parameters. foreach (var parameter in node.Command.Parameters) { if (node.Mapped.All(m => m.Item1 != parameter)) { node.Unmapped.Add(parameter); } } return(node); }
private static string ParseParameterValue(TokenStream stream, CommandTree current, CommandParameter parameter) { var value = (string)null; // Parse the value of the token (if any). var valueToken = stream.Peek(); if (valueToken?.TokenType == Token.Type.String) { // Is this a command? if (current.Command.FindCommand(valueToken.Value) == null) { if (parameter != null) { if (parameter.ParameterKind == ParameterKind.Single) { value = stream.Consume(Token.Type.String).Value; } else if (parameter.ParameterKind == ParameterKind.Flag) { throw new CommandAppException("Flags cannot be assigned a value."); } } else { // Unknown parameter value. value = stream.Consume(Token.Type.String).Value; } } } // No value? if (value == null && parameter != null) { if (parameter.ParameterKind == ParameterKind.Flag) { value = "true"; } else { switch (parameter) { case CommandOption option: throw new CommandAppException($"Option '{option.GetOptionName()}' is defined but no value has been provided."); case CommandArgument argument: throw new CommandAppException($"Argument '{argument.Value}' is defined but no value has been provided."); } } } return(value); }
public static bool IsMappedWithParent(this CommandTree tree, string name, bool longOption) { var node = tree.Parent; while (node != null) { var option = node.Command?.Parameters.OfType <CommandOption>() .FirstOrDefault(o => longOption ? o.LongName == name : o.ShortName == name); if (option != null) { if (node.Mapped.Any(p => p.Item1 == option)) { return(true); } return(false); } node = node.Parent; } return(false); }
private void ParseOption( CommandTreeParserContext context, TokenStream stream, CommandTree node, bool isLongOption) { // Get the option token. var token = stream.Consume(isLongOption ? Token.Type.LongOption : Token.Type.ShortOption); // Find the option. var option = node.FindOption(token.Value, isLongOption); if (option != null) { node.Mapped.Add((option, ParseParameterValue(stream, node, option))); return; } // Help? if (_help != null) { if (_help.ShortName?.Equals(token.Value, StringComparison.Ordinal) == true || _help.LongName?.Equals(token.Value, StringComparison.Ordinal) == true) { node.ShowHelp = true; return; } } // Parent does not have this option mapped? if (!node.IsMappedWithParent(token.Value, isLongOption)) { // Add this option as an remaining argument. var optionName = token.TokenType == Token.Type.LongOption ? $"--{token.Value}" : $"-{token.Value}"; context.AddRemainingArgument(optionName, ParseParameterValue(stream, node, null)); } }
public static CommandOption FindOption(this CommandTree tree, string name, bool longOption) { return(tree.Command.Parameters .OfType <CommandOption>() .FirstOrDefault(o => longOption ? o.LongName == name : o.ShortName == name)); }
public static CommandArgument FindArgument(this CommandTree tree, int position) { return(tree.Command.Parameters .OfType <CommandArgument>() .FirstOrDefault(c => c.Position == position)); }
public static bool HasArguments(this CommandTree tree) { return(tree.Command.Parameters.OfType <CommandArgument>().Any()); }