@@ -71,7 +71,6 @@ namespace Discord.Commands | |||||
{ | { | ||||
var parameter = parameters[i]; | var parameter = parameters[i]; | ||||
var type = parameter.ParameterType; | var type = parameter.ParameterType; | ||||
Type underlyingType = null; | |||||
if (i == 0) | if (i == 0) | ||||
{ | { | ||||
@@ -81,20 +80,18 @@ namespace Discord.Commands | |||||
continue; | continue; | ||||
} | } | ||||
// TODO: is there a better way of detecting 'params'? | |||||
bool isParams = type.IsArray && i == parameters.Length - 1; | |||||
if (isParams) | |||||
underlyingType = type.GetElementType(); | |||||
else | |||||
underlyingType = type; | |||||
//Detect 'params' | |||||
bool isMultiple = parameter.GetCustomAttribute<ParamArrayAttribute>() != null; | |||||
if (isMultiple) | |||||
type = type.GetElementType(); | |||||
var reader = Module.Service.GetTypeReader(underlyingType); | |||||
var underlyingTypeInfo = underlyingType.GetTypeInfo(); | |||||
var reader = Module.Service.GetTypeReader(type); | |||||
var typeInfo = type.GetTypeInfo(); | var typeInfo = type.GetTypeInfo(); | ||||
if (reader == null && underlyingTypeInfo.IsEnum) | |||||
//Detect enums | |||||
if (reader == null && typeInfo.IsEnum) | |||||
{ | { | ||||
reader = EnumTypeReader.GetReader(underlyingType); | |||||
reader = EnumTypeReader.GetReader(type); | |||||
Module.Service.AddTypeReader(type, reader); | Module.Service.AddTypeReader(type, reader); | ||||
} | } | ||||
@@ -110,7 +107,7 @@ namespace Discord.Commands | |||||
bool isOptional = parameter.IsOptional; | bool isOptional = parameter.IsOptional; | ||||
object defaultValue = parameter.HasDefaultValue ? parameter.DefaultValue : null; | object defaultValue = parameter.HasDefaultValue ? parameter.DefaultValue : null; | ||||
paramBuilder.Add(new CommandParameter(name, description, type, underlyingType, reader, isOptional, isRemainder, isParams, defaultValue)); | |||||
paramBuilder.Add(new CommandParameter(name, description, type, reader, isOptional, isRemainder, isMultiple, defaultValue)); | |||||
} | } | ||||
return paramBuilder.ToImmutable(); | return paramBuilder.ToImmutable(); | ||||
} | } | ||||
@@ -118,8 +115,7 @@ namespace Discord.Commands | |||||
{ | { | ||||
if (methodInfo.ReturnType != typeof(Task)) | if (methodInfo.ReturnType != typeof(Task)) | ||||
throw new InvalidOperationException("Commands must return a non-generic Task."); | throw new InvalidOperationException("Commands must return a non-generic Task."); | ||||
//TODO: Temporary reflection hack. Lets build an actual expression tree here. | |||||
return (msg, args) => | return (msg, args) => | ||||
{ | { | ||||
object[] newArgs = new object[args.Count + 1]; | object[] newArgs = new object[args.Count + 1]; | ||||
@@ -1,11 +1,9 @@ | |||||
using System; | using System; | ||||
using System.Diagnostics; | using System.Diagnostics; | ||||
using System.Reflection; | |||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
namespace Discord.Commands | namespace Discord.Commands | ||||
{ | { | ||||
//TODO: Add support for Multiple | |||||
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] | [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | ||||
public class CommandParameter | public class CommandParameter | ||||
{ | { | ||||
@@ -15,21 +13,19 @@ namespace Discord.Commands | |||||
public string Description { get; } | public string Description { get; } | ||||
public bool IsOptional { get; } | public bool IsOptional { get; } | ||||
public bool IsRemainder { get; } | public bool IsRemainder { get; } | ||||
public bool IsParams { get; } | |||||
public bool IsMultiple { get; } | |||||
public Type Type { get; } | public Type Type { get; } | ||||
public Type UnderlyingType { get; } | |||||
internal object DefaultValue { get; } | internal object DefaultValue { get; } | ||||
public CommandParameter(string name, string description, Type type, Type underlyingType, TypeReader reader, bool isOptional, bool isRemainder, bool isParams, object defaultValue) | |||||
public CommandParameter(string name, string description, Type type, TypeReader reader, bool isOptional, bool isRemainder, bool isMultiple, object defaultValue) | |||||
{ | { | ||||
Name = name; | Name = name; | ||||
Description = description; | Description = description; | ||||
Type = type; | Type = type; | ||||
UnderlyingType = underlyingType; | |||||
_reader = reader; | _reader = reader; | ||||
IsOptional = isOptional; | IsOptional = isOptional; | ||||
IsRemainder = isRemainder; | IsRemainder = isRemainder; | ||||
IsParams = isParams; | |||||
IsMultiple = isMultiple; | |||||
DefaultValue = defaultValue; | DefaultValue = defaultValue; | ||||
} | } | ||||
@@ -23,8 +23,8 @@ namespace Discord.Commands | |||||
int endPos = input.Length; | int endPos = input.Length; | ||||
var curPart = ParserPart.None; | var curPart = ParserPart.None; | ||||
int lastArgEndPos = int.MinValue; | int lastArgEndPos = int.MinValue; | ||||
IList<object> paramsList = null; // TODO: could we use a better type? | |||||
var argList = ImmutableArray.CreateBuilder<object>(); | var argList = ImmutableArray.CreateBuilder<object>(); | ||||
List<object> paramsList = null; // TODO: could we use a better type? | |||||
bool isEscaping = false; | bool isEscaping = false; | ||||
char c; | char c; | ||||
@@ -74,10 +74,6 @@ namespace Discord.Commands | |||||
argBuilder.Append(c); | argBuilder.Append(c); | ||||
continue; | continue; | ||||
} | } | ||||
if (curParam != null && curParam.IsParams) | |||||
{ | |||||
paramsList = new List<object>(); | |||||
} | |||||
if (c == '\"') | if (c == '\"') | ||||
{ | { | ||||
curPart = ParserPart.QuotedParameter; | curPart = ParserPart.QuotedParameter; | ||||
@@ -119,17 +115,17 @@ namespace Discord.Commands | |||||
if (!typeReaderResult.IsSuccess) | if (!typeReaderResult.IsSuccess) | ||||
return ParseResult.FromError(typeReaderResult); | return ParseResult.FromError(typeReaderResult); | ||||
if (curParam.IsParams) | |||||
if (curParam.IsMultiple) | |||||
{ | { | ||||
if (paramsList == null) | |||||
paramsList = new List<object>(); | |||||
paramsList.Add(typeReaderResult.Value); | paramsList.Add(typeReaderResult.Value); | ||||
if (curPos == endPos) | if (curPos == endPos) | ||||
{ | { | ||||
// TODO: can this logic be improved? | |||||
object[] _params = paramsList.ToArray(); | |||||
Array realParams = Array.CreateInstance(curParam.UnderlyingType, _params.Length); | |||||
for (int i = 0; i < _params.Length; i++) | |||||
realParams.SetValue(Convert.ChangeType(_params[i], curParam.UnderlyingType), i); | |||||
Array realParams = Array.CreateInstance(curParam.Type, paramsList.Count); | |||||
for (int i = 0; i < paramsList.Count; i++) | |||||
realParams.SetValue(Convert.ChangeType(paramsList[i], curParam.Type), i); | |||||
argList.Add(realParams); | argList.Add(realParams); | ||||