Example #1
0
        private static CommandSettings CreateSettings(ITypeResolver resolver, Type settingsType)
        {
            if (resolver.Resolve(settingsType) is CommandSettings settings)
            {
                return(settings);
            }

            throw CommandParseException.CouldNotCreateSettings(settingsType);
        }
Example #2
0
    private static IEnumerable <CommandTreeToken> ScanOptions(CommandTreeTokenizerContext context, TextBuffer reader)
    {
        var result = new List <CommandTreeToken>();

        var position = reader.Position;

        reader.Consume('-');
        context.AddRemaining('-');

        if (!reader.TryPeek(out var character))
        {
            var token = new CommandTreeToken(CommandTreeToken.Kind.ShortOption, position, "-", "-");
            throw CommandParseException.OptionHasNoName(reader.Original, token);
        }

        switch (character)
        {
        case '-':
            var option = ScanLongOption(context, reader, position);
            if (option != null)
            {
                result.Add(option);
            }

            break;

        default:
            result.AddRange(ScanShortOptions(context, reader, position));
            break;
        }

        if (reader.TryPeek(out character))
        {
            // Encountered a separator?
            if (character == '=' || character == ':')
            {
                reader.Read(); // Consume
                context.AddRemaining(character);

                if (!reader.TryPeek(out _))
                {
                    var token = new CommandTreeToken(CommandTreeToken.Kind.String, reader.Position, "=", "=");
                    throw CommandParseException.OptionValueWasExpected(reader.Original, token);
                }

                result.Add(ScanString(context, reader));
            }
        }

        return(result);
    }
Example #3
0
    public ICommand CreateCommand(ITypeResolver resolver)
    {
        if (Command.Delegate != null)
        {
            return(new DelegateCommand(Command.Delegate));
        }

        if (resolver.Resolve(Command.CommandType) is ICommand command)
        {
            return(command);
        }

        throw CommandParseException.CouldNotCreateCommand(Command.CommandType);
    }
Example #4
0
    private static IEnumerable <CommandTreeToken> ScanShortOptions(CommandTreeTokenizerContext context, TextBuffer reader, int position)
    {
        var result = new List <CommandTreeToken>();

        while (!reader.ReachedEnd)
        {
            var current = reader.Peek();
            if (char.IsWhiteSpace(current))
            {
                break;
            }

            // Encountered a separator?
            if (current == '=' || current == ':')
            {
                break;
            }

            if (char.IsLetter(current))
            {
                context.AddRemaining(current);
                reader.Read(); // Consume

                var value = current.ToString(CultureInfo.InvariantCulture);
                result.Add(result.Count == 0
                    ? new CommandTreeToken(CommandTreeToken.Kind.ShortOption, position, value, $"-{value}")
                    : new CommandTreeToken(CommandTreeToken.Kind.ShortOption, position + result.Count, value, value));
            }
            else
            {
                // Create a token representing the short option.
                var tokenPosition = position + 1 + result.Count;
                var represntation = current.ToString(CultureInfo.InvariantCulture);
                var token         = new CommandTreeToken(CommandTreeToken.Kind.ShortOption, tokenPosition, represntation, represntation);
                throw CommandParseException.InvalidShortOptionName(reader.Original, token);
            }
        }

        if (result.Count > 1)
        {
            foreach (var item in result)
            {
                item.IsGrouped = true;
            }
        }

        return(result);
    }
    public CommandTreeToken Expect(CommandTreeToken.Kind expected)
    {
        if (Current == null)
        {
            throw CommandParseException.ExpectedTokenButFoundNull(expected);
        }

        var found = Current.TokenKind;

        if (expected != found)
        {
            throw CommandParseException.ExpectedTokenButFoundOther(expected, found);
        }

        return(Current);
    }
Example #6
0
        public void CommandParseException_Should_Contain_Correct_Message_Single()
        {
            var cmdMock = new Mock <ICommandLineCommand>();

            cmdMock.SetupGet(_ => _.Name).Returns("test");

            var exceptionList = new List <Exception>
            {
                new Exception("msg1")
            };

            var parseException = new CommandParseException(cmdMock.Object, exceptionList.AsReadOnly());
            var msg            = parseException.Message;
            var expected       = @"Unable to parse command 'test' reason: msg1";

            Assert.Equal(expected, msg);
        }
Example #7
0
    private void ParseOption(
        CommandTreeParserContext context,
        CommandTreeTokenStream stream,
        CommandTreeToken token,
        CommandTree node,
        bool isLongOption)
    {
        // Consume the option token.
        stream.Consume(isLongOption ? CommandTreeToken.Kind.LongOption : CommandTreeToken.Kind.ShortOption);

        if (context.State == State.Normal)
        {
            // Find the option.
            var option = node.FindOption(token.Value, isLongOption, CaseSensitivity);
            if (option != null)
            {
                node.Mapped.Add(new MappedCommandParameter(
                                    option, ParseOptionValue(context, stream, token, node, option)));

                return;
            }

            // Help?
            if (_help?.IsMatch(token.Value) == true)
            {
                node.ShowHelp = true;
                return;
            }
        }

        if (context.State == State.Remaining)
        {
            ParseOptionValue(context, stream, token, node, null);
            return;
        }

        if (context.ParsingMode == ParsingMode.Strict)
        {
            throw CommandParseException.UnknownOption(context.Arguments, token);
        }
        else
        {
            ParseOptionValue(context, stream, token, node, null);
        }
    }
Example #8
0
    private static CommandTreeToken ScanLongOption(CommandTreeTokenizerContext context, TextBuffer reader, int position)
    {
        reader.Consume('-');
        context.AddRemaining('-');

        if (reader.ReachedEnd)
        {
            // Rest of the arguments are remaining ones.
            context.Mode = Mode.Remaining;
            return(new CommandTreeToken(CommandTreeToken.Kind.Remaining, position, "--", "--"));
        }

        var name = ScanString(context, reader, new[] { '=', ':' });

        // Perform validation of the name.
        if (name.Value.Length == 0)
        {
            throw CommandParseException.LongOptionNameIsMissing(reader, position);
        }

        if (name.Value.Length == 1)
        {
            throw CommandParseException.LongOptionNameIsOneCharacter(reader, position, name.Value);
        }

        if (char.IsDigit(name.Value[0]))
        {
            throw CommandParseException.LongOptionNameStartWithDigit(reader, position, name.Value);
        }

        for (var index = 0; index < name.Value.Length; index++)
        {
            if (!char.IsLetterOrDigit(name.Value[index]) && name.Value[index] != '-' && name.Value[index] != '_')
            {
                throw CommandParseException.LongOptionNameContainSymbol(reader, position + 2 + index, name.Value[index]);
            }
        }

        return(new CommandTreeToken(CommandTreeToken.Kind.LongOption, position, name.Value, $"--{name.Value}"));
    }
Example #9
0
    private static CommandTreeToken ScanQuotedString(CommandTreeTokenizerContext context, TextBuffer reader)
    {
        var position = reader.Position;

        context.FlushRemaining();
        reader.Consume('\"');

        var builder    = new StringBuilder();
        var terminated = false;

        while (!reader.ReachedEnd)
        {
            var character = reader.Peek();
            if (character == '\"')
            {
                terminated = true;
                reader.Read();
                break;
            }

            builder.Append(reader.Read());
        }

        if (!terminated)
        {
            var unterminatedQuote = builder.ToString();
            var token             = new CommandTreeToken(CommandTreeToken.Kind.String, position, unterminatedQuote, $"\"{unterminatedQuote}");
            throw CommandParseException.UnterminatedQuote(reader.Original, token);
        }

        var quotedString = builder.ToString();

        // Add to the context
        context.AddRemaining(quotedString);

        return(new CommandTreeToken(
                   CommandTreeToken.Kind.String,
                   position, quotedString,
                   quotedString));
    }
Example #10
0
    private CommandTree ParseCommand(
        CommandTreeParserContext context,
        ICommandContainer current,
        CommandTree?parent,
        CommandTreeTokenStream stream)
    {
        // Find the command.
        var commandToken = stream.Consume(CommandTreeToken.Kind.String);

        if (commandToken == null)
        {
            throw new CommandRuntimeException("Could not consume token when parsing command.");
        }

        var command = current.FindCommand(commandToken.Value, CaseSensitivity);

        if (command == null)
        {
            throw CommandParseException.UnknownCommand(_configuration, parent, context.Arguments, commandToken);
        }

        return(ParseCommandParameters(context, command, parent, stream));
    }
Example #11
0
    public CommandTreeParserResult Parse(IEnumerable <string> args)
    {
        var context = new CommandTreeParserContext(args, _parsingMode);

        var tokenizerResult = CommandTreeTokenizer.Tokenize(context.Arguments);
        var tokens          = tokenizerResult.Tokens;
        var rawRemaining    = tokenizerResult.Remaining;

        var result = default(CommandTree);

        if (tokens.Count > 0)
        {
            // Not a command?
            var token = tokens.Current;
            if (token == null)
            {
                // Should not happen, but the compiler isn't
                // smart enough to realize this...
                throw new CommandRuntimeException("Could not get current token.");
            }

            if (token.TokenKind != CommandTreeToken.Kind.String)
            {
                // Got a default command?
                if (_configuration.DefaultCommand != null)
                {
                    result = ParseCommandParameters(context, _configuration.DefaultCommand, null, tokens);
                    return(new CommandTreeParserResult(
                               result, new RemainingArguments(context.GetRemainingArguments(), rawRemaining)));
                }

                // Show help?
                if (_help?.IsMatch(token.Value) == true)
                {
                    return(new CommandTreeParserResult(
                               null, new RemainingArguments(context.GetRemainingArguments(), rawRemaining)));
                }

                // Unexpected option.
                throw CommandParseException.UnexpectedOption(context.Arguments, token);
            }

            // Does the token value match a command?
            var command = _configuration.FindCommand(token.Value, CaseSensitivity);
            if (command == null)
            {
                if (_configuration.DefaultCommand != null)
                {
                    result = ParseCommandParameters(context, _configuration.DefaultCommand, null, tokens);
                    return(new CommandTreeParserResult(
                               result, new RemainingArguments(context.GetRemainingArguments(), rawRemaining)));
                }
            }

            // Parse the command.
            result = ParseCommand(context, _configuration, null, tokens);
        }
        else
        {
            // Is there a default command?
            if (_configuration.DefaultCommand != null)
            {
                result = ParseCommandParameters(context, _configuration.DefaultCommand, null, tokens);
            }
        }

        return(new CommandTreeParserResult(
                   result, new RemainingArguments(context.GetRemainingArguments(), rawRemaining)));
    }
Example #12
0
    private string?ParseOptionValue(
        CommandTreeParserContext context,
        CommandTreeTokenStream stream,
        CommandTreeToken token,
        CommandTree current,
        CommandParameter?parameter)
    {
        var value = default(string);

        // Parse the value of the token (if any).
        var valueToken = stream.Peek();

        if (valueToken?.TokenKind == CommandTreeToken.Kind.String)
        {
            var parseValue = true;
            if (token.TokenKind == CommandTreeToken.Kind.ShortOption && token.IsGrouped)
            {
                parseValue = false;
            }

            if (context.State == State.Normal && parseValue)
            {
                // Is this a command?
                if (current.Command.FindCommand(valueToken.Value, CaseSensitivity) == null)
                {
                    if (parameter != null)
                    {
                        if (parameter.ParameterKind == ParameterKind.Flag)
                        {
                            if (!CliConstants.AcceptedBooleanValues.Contains(valueToken.Value, StringComparer.OrdinalIgnoreCase))
                            {
                                // Flags cannot be assigned a value.
                                throw CommandParseException.CannotAssignValueToFlag(context.Arguments, token);
                            }
                        }

                        value = stream.Consume(CommandTreeToken.Kind.String)?.Value;
                    }
                    else
                    {
                        // Unknown parameter value.
                        value = stream.Consume(CommandTreeToken.Kind.String)?.Value;

                        // In relaxed parsing mode?
                        if (context.ParsingMode == ParsingMode.Relaxed)
                        {
                            context.AddRemainingArgument(token.Value, value);
                        }
                    }
                }
            }
            else
            {
                context.AddRemainingArgument(token.Value, parseValue ? valueToken.Value : null);
            }
        }
        else
        {
            if (context.State == State.Remaining || context.ParsingMode == ParsingMode.Relaxed)
            {
                context.AddRemainingArgument(token.Value, null);
            }
        }

        // No value?
        if (context.State == State.Normal)
        {
            if (value == null && parameter != null)
            {
                if (parameter.ParameterKind == ParameterKind.Flag)
                {
                    value = "true";
                }
                else
                {
                    if (parameter is CommandOption option)
                    {
                        if (parameter.IsFlagValue())
                        {
                            return(null);
                        }

                        throw CommandParseException.OptionHasNoValue(context.Arguments, token, option);
                    }
                    else
                    {
                        // This should not happen at all. If it does, it's because we've added a new
                        // option type which isn't a CommandOption for some reason.
                        throw new InvalidOperationException($"Found invalid parameter type '{parameter.GetType().FullName}'.");
                    }
                }
            }
        }

        return(value);
    }
Example #13
0
    private void ParseString(
        CommandTreeParserContext context,
        CommandTreeTokenStream stream,
        CommandTree node)
    {
        if (context.State == State.Remaining)
        {
            stream.Consume(CommandTreeToken.Kind.String);
            return;
        }

        var token = stream.Expect(CommandTreeToken.Kind.String);

        // Command?
        var command = node.Command.FindCommand(token.Value, CaseSensitivity);

        if (command != null)
        {
            if (context.State == State.Normal)
            {
                node.Next = ParseCommand(context, node.Command, node, stream);
            }

            return;
        }

        // Current command has no arguments?
        if (!node.HasArguments())
        {
            throw CommandParseException.UnknownCommand(_configuration, node, context.Arguments, token);
        }

        // Argument?
        var parameter = node.FindArgument(context.CurrentArgumentPosition);

        if (parameter == null)
        {
            // No parameters left. Any commands after this?
            if (node.Command.Children.Count > 0 || node.Command.IsDefaultCommand)
            {
                throw CommandParseException.UnknownCommand(_configuration, node, context.Arguments, token);
            }

            throw CommandParseException.CouldNotMatchArgument(context.Arguments, token);
        }

        // Yes, this was an argument.
        if (parameter.ParameterKind == ParameterKind.Vector)
        {
            // Vector
            var current = stream.Current;
            while (current?.TokenKind == CommandTreeToken.Kind.String)
            {
                var value = stream.Consume(CommandTreeToken.Kind.String)?.Value;
                node.Mapped.Add(new MappedCommandParameter(parameter, value));
                current = stream.Current;
            }
        }
        else
        {
            // Scalar
            var value = stream.Consume(CommandTreeToken.Kind.String)?.Value;
            node.Mapped.Add(new MappedCommandParameter(parameter, value));
            context.IncreaseArgumentPosition();
        }
    }