Added new parameter scoring, support multiple matches

This commit is contained in:
RogueException
2016-08-21 11:03:50 -03:00
parent ed7710fbef
commit 324664917d
14 changed files with 316 additions and 177 deletions

View File

@@ -1,8 +1,5 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
@@ -16,9 +13,6 @@ namespace Discord.Commands
Parameter,
QuotedParameter
}
private static readonly MethodInfo _convertArrayMethod = typeof(CommandParser).GetTypeInfo().GetDeclaredMethod(nameof(ConvertParamsList));
private static readonly ConcurrentDictionary<Type, Func<List<object>, object>> _arrayConverters = new ConcurrentDictionary<Type, Func<List<object>, object>>();
public static async Task<ParseResult> ParseArgs(Command command, IMessage context, string input, int startPos)
{
@@ -27,9 +21,10 @@ namespace Discord.Commands
int endPos = input.Length;
var curPart = ParserPart.None;
int lastArgEndPos = int.MinValue;
var argList = ImmutableArray.CreateBuilder<object>();
List<object> paramsList = null; // TODO: could we use a better type?
var argList = ImmutableArray.CreateBuilder<TypeReaderResult>();
ImmutableArray<TypeReaderResult>.Builder paramList = null;
bool isEscaping = false;
bool hasMultipleMatches = false;
char c;
for (int curPos = startPos; curPos <= endPos; curPos++)
@@ -117,30 +112,28 @@ namespace Discord.Commands
var typeReaderResult = await curParam.Parse(context, argString).ConfigureAwait(false);
if (!typeReaderResult.IsSuccess)
return ParseResult.FromError(typeReaderResult);
{
if (typeReaderResult.Error == CommandError.MultipleMatches)
hasMultipleMatches = true;
else
return ParseResult.FromError(typeReaderResult);
}
if (curParam.IsMultiple)
{
if (paramsList == null)
paramsList = new List<object>();
paramsList.Add(typeReaderResult.Value);
if (paramList == null)
paramList = ImmutableArray.CreateBuilder<TypeReaderResult>();
paramList.Add(typeReaderResult);
if (curPos == endPos)
{
var func = _arrayConverters.GetOrAdd(curParam.ElementType, t =>
{
var method = _convertArrayMethod.MakeGenericMethod(t);
return (Func<List<object>, object>)method.CreateDelegate(typeof(Func<List<object>, object>));
});
argList.Add(func.Invoke(paramsList));
curParam = null;
curPart = ParserPart.None;
}
}
else
{
argList.Add(typeReaderResult.Value);
argList.Add(typeReaderResult);
curParam = null;
curPart = ParserPart.None;
@@ -154,34 +147,24 @@ namespace Discord.Commands
var typeReaderResult = await curParam.Parse(context, argBuilder.ToString()).ConfigureAwait(false);
if (!typeReaderResult.IsSuccess)
return ParseResult.FromError(typeReaderResult);
argList.Add(typeReaderResult.Value);
argList.Add(typeReaderResult);
}
if (isEscaping)
return ParseResult.FromError(CommandError.ParseFailed, "Input text may not end on an incomplete escape.");
if (curPart == ParserPart.QuotedParameter)
return ParseResult.FromError(CommandError.ParseFailed, "A quoted parameter is incomplete");
if (argList.Count < command.Parameters.Count)
//Add missing optionals
for (int i = paramList.Count; i < command.Parameters.Count; i++)
{
for (int i = argList.Count; i < command.Parameters.Count; i++)
{
var param = command.Parameters[i];
if (!param.IsOptional)
return ParseResult.FromError(CommandError.BadArgCount, "The input text has too few parameters.");
argList.Add(param.DefaultValue);
}
var param = command.Parameters[i];
if (!param.IsOptional)
return ParseResult.FromError(CommandError.BadArgCount, "The input text has too few parameters.");
argList.Add(TypeReaderResult.FromSuccess(param.DefaultValue));
}
return ParseResult.FromSuccess(argList.ToImmutable());
}
private static T[] ConvertParamsList<T>(List<object> paramsList)
{
var array = new T[paramsList.Count];
for (int i = 0; i < array.Length; i++)
array[i] = (T)paramsList[i];
return array;
return ParseResult.FromSuccess(argList.ToImmutable(), paramList?.ToImmutable());
}
}
}