示例#1
0
        public override Task <ArgsParseResult <int> > Parse(IImmutableList <string> args, Type[] genericTypes)
        {
            string str = args[0];

            try
            {
                int number = int.Parse(str);
                if (number < _minValue)
                {
                    return(Task.FromResult(ArgsParseResult <int> .Failure(
                                               $"'{str}' cannot be below {_minValue}", ErrorRelevanceConfidence.Likely)));
                }
                if (number > _maxValue)
                {
                    return(Task.FromResult(ArgsParseResult <int> .Failure(
                                               $"'{str}' cannot be above {_maxValue}", ErrorRelevanceConfidence.Likely)));
                }
                ArgsParseResult <int> result = ArgsParseResult <int> .Success(number, args.Skip(1).ToImmutableList());

                return(Task.FromResult(result));
            }
            catch (FormatException)
            {
                return(Task.FromResult(ArgsParseResult <int> .Failure($"did not recognize '{str}' as a number")));
            }
            catch (OverflowException)
            {
                return(Task.FromResult(ArgsParseResult <int> .Failure(
                                           $"'{str}' is out of range", ErrorRelevanceConfidence.Likely)));
            }
        }
示例#2
0
        public override Task <ArgsParseResult <T> > Parse(IImmutableList <string> args, Type[] genericTypes)
        {
            string str   = args[0];
            var    match = _regex.Match(str);

            if (!match.Success)
            {
                return(Task.FromResult(ArgsParseResult <T> .Failure(
                                           $"did not recognize '{str}' as a '{_prefix}'-prefixed number")));
            }
            try
            {
                int number = int.Parse(match.Groups["number"].Value);
                if (number < _minValue)
                {
                    return(Task.FromResult(ArgsParseResult <T> .Failure(
                                               $"'{str}' cannot be less than {_prefix}{_minValue}", ErrorRelevanceConfidence.Likely)));
                }
                if (number > _maxValue)
                {
                    return(Task.FromResult(ArgsParseResult <T> .Failure(
                                               $"'{str}' cannot be more than {_prefix}{_maxValue}", ErrorRelevanceConfidence.Likely)));
                }
                var value = new T {
                    Number = number
                };
                return(Task.FromResult(ArgsParseResult <T> .Success(value, args.Skip(1).ToImmutableList())));
            }
            catch (OverflowException)
            {
                return(Task.FromResult(ArgsParseResult <T> .Failure(
                                           $"'{str}' is out of range", ErrorRelevanceConfidence.Likely)));
            }
        }
        public override Task <ArgsParseResult <Percentage> > Parse(IImmutableList <string> args, Type[] genericTypes)
        {
            string percentageStr = args[0];

            if (!percentageStr.EndsWith('%'))
            {
                return(Task.FromResult(ArgsParseResult <Percentage> .Failure("percentages must end in '%'")));
            }
            string doubleStr = percentageStr[..^ 1];
示例#4
0
        public override async Task <ArgsParseResult <User> > Parse(IImmutableList <string> args, Type[] genericTypes)
        {
            string simpleName = args[0].ToLower();
            bool   isPrefixed = simpleName.StartsWith('@');

            if (isPrefixed)
            {
                simpleName = simpleName.Substring(1);
            }
            User?user = await _userRepo.FindBySimpleName(simpleName);

            return(user == null
                ? ArgsParseResult <User> .Failure($"did not recognize a user with the name '{simpleName}'",
                                                  isPrefixed?ErrorRelevanceConfidence.Likely : ErrorRelevanceConfidence.Default)
                : ArgsParseResult <User> .Success(user, args.Skip(1).ToImmutableList()));
        }
示例#5
0
        public override Task <ArgsParseResult <Role> > Parse(IImmutableList <string> args, Type[] genericTypes)
        {
            string roleToParse = args[0];
            ArgsParseResult <Role> result;

            try
            {
                Role parsedRole = (Role)Enum.Parse(typeof(Role), roleToParse, ignoreCase: true);
                result = ArgsParseResult <Role> .Success(parsedRole, args.Skip(1).ToImmutableList());
            }
            catch (ArgumentException)
            {
                result = ArgsParseResult <Role> .Failure($"Did not find a role named '{roleToParse}'");
            }
            return(Task.FromResult(result));
        }
示例#6
0
        public override Task <ArgsParseResult <HexColor> > Parse(IImmutableList <string> args, Type[] genericTypes)
        {
            Match colorMatch = _regex.Match(args[0]);

            if (colorMatch.Success)
            {
                var color = new HexColor(colorMatch.Value.ToUpper());
                return(Task.FromResult(ArgsParseResult <HexColor> .Success(color, args.Skip(1).ToImmutableList())));
            }
            else
            {
                return(Task.FromResult(args[0].StartsWith("#")
                    ? ArgsParseResult <HexColor> .Failure(
                                           $"'{args[0]}' must be a 6-character hex code consisting of 0-9 and A-F, " +
                                           "for example '#FF0000' for pure red.", ErrorRelevanceConfidence.Likely)
                    : ArgsParseResult <HexColor> .Failure($"'{args[0]}' is not a valid hex color")));
            }
        }
示例#7
0
        public override Task <ArgsParseResult <Instant> > Parse(IImmutableList <string> args, Type[] genericTypes)
        {
            if (args.Count >= 2)
            {
                // try with 2 arguments first, in case it contains a space instead of 'T'
                string str = $"{args[0]}T{args[1]}";
                ParseResult <Instant> resultFromTwoArgs = InstantPattern.ExtendedIso.Parse(str);
                if (resultFromTwoArgs.Success)
                {
                    return(Task.FromResult(ArgsParseResult <Instant> .Success(
                                               resultFromTwoArgs.Value, args.Skip(2).ToImmutableList())));
                }
            }
            ParseResult <Instant> resultFromOneArgs = InstantPattern.ExtendedIso.Parse(args[0]);

            return(Task.FromResult(resultFromOneArgs.Success
                ? ArgsParseResult <Instant> .Success(resultFromOneArgs.Value, args.Skip(1).ToImmutableList())
                : ArgsParseResult <Instant> .Failure($"did not recognize '{args[0]}' as a UTC-instant")));
        }
示例#8
0
        public override async Task <ArgsParseResult <AnyOrder> > Parse(
            IImmutableList <string> args,
            Type[] genericTypes)
        {
            var argList  = args.Take(genericTypes.Length).ToList();
            var failures = new List <Failure>();

            foreach (var argsPermutation in Permutations(argList))
            {
                ArgsParseResult <List <object> > parseResult = await _argsParser
                                                               .ParseRaw(argsPermutation.ToImmutableList(), genericTypes);

                if (parseResult.SuccessResult == null)
                {
                    Debug.Assert(parseResult.Failures.Any());
                    failures.AddRange(parseResult.Failures);
                    continue;
                }
                List <object> items = parseResult.SuccessResult.Value.Result;
                Type          type  = items.Count switch
                {
                    2 => typeof(AnyOrder <,>),
                    3 => typeof(AnyOrder <, ,>),
                    4 => typeof(AnyOrder <, , ,>),
                    var num => throw new InvalidOperationException(
                              $"An implementation of {typeof(AnyOrder)} for {num} generic arguments " +
                              "needs to be implemented and wired up where this exception is thrown. " +
                              "But do you _really_ want this many arguments in any order?")
                };
                ConstructorInfo?constructor = type.MakeGenericType(genericTypes).GetConstructor(genericTypes);
                if (constructor == null)
                {
                    throw new InvalidOperationException($"{type} needs a constructor with {items.Count} parameters.");
                }
                return(ArgsParseResult <AnyOrder> .Success(
                           parseResult.Failures,
                           (AnyOrder)constructor.Invoke(items.ToArray()),
                           parseResult.SuccessResult.Value.RemainingArgs));
            }
            Debug.Assert(failures.Any());
            return(ArgsParseResult <AnyOrder> .Failure(failures.ToImmutableList()));
        }
    }
示例#9
0
        public override Task <ArgsParseResult <TimeSpan> > Parse(IImmutableList <string> args, Type[] genericTypes)
        {
            string str   = args[0];
            var    match = Regex.Match(str);

            if (match.Success)
            {
                try
                {
                    string weeks    = match.Groups["weeks"].Value;
                    string days     = match.Groups["days"].Value;
                    string hours    = match.Groups["hours"].Value;
                    string minutes  = match.Groups["minutes"].Value;
                    string seconds  = match.Groups["seconds"].Value;
                    var    timeSpan = new TimeSpan(
                        days: (weeks.Length > 0 ? int.Parse(weeks) : 0) * 7
                        + (days.Length > 0 ? int.Parse(days) : 0),
                        hours: hours.Length > 0 ? int.Parse(hours) : 0,
                        minutes: minutes.Length > 0 ? int.Parse(minutes) : 0,
                        seconds: seconds.Length > 0 ? int.Parse(seconds) : 0
                        );
                    return(Task.FromResult(ArgsParseResult <TimeSpan> .Success(
                                               timeSpan, args.Skip(1).ToImmutableList())));
                }
                catch (FormatException)
                {
                    return(Task.FromResult(ArgsParseResult <TimeSpan> .Failure(
                                               $"did not recognize '{str}' as a duration")));
                }
                catch (OverflowException)
                {
                    return(Task.FromResult(ArgsParseResult <TimeSpan> .Failure(
                                               $"the duration described by '{str}' is out of range", ErrorRelevanceConfidence.Likely)));
                }
            }
            else
            {
                return(Task.FromResult(ArgsParseResult <TimeSpan> .Failure(
                                           $"did not recognize '{str}' as a duration in the form " +
                                           "'<weeks>w<days>d<hours>h<minutes>m<seconds>s' (zeroes may be omitted, e.g. '1d12h')")));
            }
        }
示例#10
0
        public override Task <ArgsParseResult <PkmnSpecies> > Parse(IImmutableList <string> args, Type[] genericTypes)
        {
            if (!args[0].StartsWith("#"))
            {
                string normalizedName = NormalizeName(args[0]);
                if (_nameLookup.TryGetValue(normalizedName, out PkmnSpecies? speciesFromName))
                {
                    return(Task.FromResult(ArgsParseResult <PkmnSpecies> .Success(
                                               speciesFromName !, args.Skip(1).ToImmutableList())));
                }
                if (args.Count >= 2)
                {
                    string normalizedNameTwoArgs = NormalizeName(args[0] + ' ' + args[1]);
                    if (_nameLookup.TryGetValue(normalizedNameTwoArgs, out PkmnSpecies? speciesFromTwoArgsName))
                    {
                        return(Task.FromResult(ArgsParseResult <PkmnSpecies> .Success(
                                                   speciesFromTwoArgsName, args.Skip(2).ToImmutableList())));
                    }
                }
                if (int.TryParse(normalizedName, out _))
                {
                    return(Task.FromResult(ArgsParseResult <PkmnSpecies> .Failure(
                                               "Please prefix with '#' to supply and pokedex number", ErrorRelevanceConfidence.Likely)));
                }
                else
                {
                    return(Task.FromResult(ArgsParseResult <PkmnSpecies> .Failure(
                                               $"No pokemon with the name '{normalizedName}' was recognized. " +
                                               "Please supply a valid name, or prefix with '#' to supply and pokedex number instead")));
                }
            }
            string speciesId = args[0].Substring(startIndex: 1);

            return(Task.FromResult(_idLookup.TryGetValue(speciesId.TrimStart('0'), out var species)
                ? ArgsParseResult <PkmnSpecies> .Success(species, args.Skip(1).ToImmutableList())
                : ArgsParseResult <PkmnSpecies> .Failure($"did not recognize species '{args[0]}'",
                                                         ErrorRelevanceConfidence.Likely)
                                   ));
        }
        public override async Task <ArgsParseResult <AnyOrder> > Parse(
            IImmutableList <string> args,
            Type[] genericTypes)
        {
            var failures = new List <Failure>();
            ArgsParseResult <AnyOrder>?mostSpecificSuccess = null;

            foreach (IList <int> permutationIndexes in Permutations(Enumerable.Range(0, genericTypes.Length).ToList()))
            {
                ArgsParseResult <List <object> > parseResult = await _argsParser
                                                               .ParseRaw(args, permutationIndexes.Select(i => genericTypes[i]));

                if (parseResult.SuccessResult == null)
                {
                    Debug.Assert(parseResult.Failures.Any());
                    failures.AddRange(parseResult.Failures);
                    continue;
                }
                if (mostSpecificSuccess != null &&
                    mostSpecificSuccess.Value.SuccessResult !.Value.RemainingArgs.Count <=
                    parseResult.SuccessResult.Value.RemainingArgs.Count)
                {
                    // if there already is an equally or more specific result, don't even bother processing this one
                    continue;
                }
                List <object> items = parseResult.SuccessResult.Value.Result;
                Type          type  = items.Count switch
                {
                    2 => typeof(AnyOrder <,>),
                    3 => typeof(AnyOrder <, ,>),
                    4 => typeof(AnyOrder <, , ,>),
                    var num => throw new InvalidOperationException(
                              $"An implementation of {typeof(AnyOrder)} for {num} generic arguments " +
                              "needs to be implemented and wired up where this exception is thrown. " +
                              "But do you _really_ want this many arguments in any order?")
                };
                ConstructorInfo?constructor = type.MakeGenericType(genericTypes).GetConstructor(genericTypes);
                if (constructor == null)
                {
                    throw new InvalidOperationException($"{type} needs a constructor with {items.Count} parameters.");
                }
                // If our permutation is [2,0,1] and our result is [c,a,b], we need to restore the
                // arguments' original order [a,b,c] before passing them to the AnyOrder constructor.
                object?[] itemsUnshuffled = permutationIndexes.Zip(items)
                                            .OrderBy(tpl => tpl.First)
                                            .Select(tpl => tpl.Second)
                                            .ToArray();
                mostSpecificSuccess = ArgsParseResult <AnyOrder> .Success(
                    parseResult.Failures,
                    (AnyOrder)constructor.Invoke(itemsUnshuffled),
                    parseResult.SuccessResult.Value.RemainingArgs);

                if (parseResult.SuccessResult.Value.RemainingArgs.Count == 0)
                {
                    break; // we won't get any better than this
                }
            }
            if (mostSpecificSuccess != null)
            {
                return(mostSpecificSuccess.Value);
            }
            Debug.Assert(failures.Any());
            return(ArgsParseResult <AnyOrder> .Failure(failures.ToImmutableList()));
        }
    }