| @@ -66,6 +66,7 @@ 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) | ||||
| { | { | ||||
| @@ -75,10 +76,24 @@ namespace Discord.Commands | |||||
| continue; | continue; | ||||
| } | } | ||||
| var typeInfo = type.GetTypeInfo(); | |||||
| var reader = Module.Service.GetTypeReader(type); | var reader = Module.Service.GetTypeReader(type); | ||||
| if (reader == null && typeInfo.IsEnum) | |||||
| // TODO: is there a better way of detecting 'params'? | |||||
| bool isParams = type.IsArray && i == parameters.Length - 1; | |||||
| if (isParams) | |||||
| { | |||||
| underlyingType = type.GetElementType(); | |||||
| reader = Module.Service.GetTypeReader(underlyingType); | |||||
| } | |||||
| else | |||||
| { | |||||
| underlyingType = type; | |||||
| } | |||||
| var underlyingTypeInfo = underlyingType.GetTypeInfo(); | |||||
| var typeInfo = type.GetTypeInfo(); | |||||
| if (reader == null && underlyingTypeInfo.IsEnum) | |||||
| { | { | ||||
| reader = EnumTypeReader.GetReader(type); | reader = EnumTypeReader.GetReader(type); | ||||
| Module.Service.AddTypeReader(type, reader); | Module.Service.AddTypeReader(type, reader); | ||||
| @@ -96,7 +111,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, reader, isOptional, isRemainder, defaultValue)); | |||||
| paramBuilder.Add(new CommandParameter(name, description, type, underlyingType, reader, isOptional, isRemainder, isParams, defaultValue)); | |||||
| } | } | ||||
| return paramBuilder.ToImmutable(); | return paramBuilder.ToImmutable(); | ||||
| } | } | ||||
| @@ -15,17 +15,21 @@ 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 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, TypeReader reader, bool isOptional, bool isRemainder, object defaultValue) | |||||
| public CommandParameter(string name, string description, Type type, Type underlyingType, TypeReader reader, bool isOptional, bool isRemainder, bool isParams, 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; | |||||
| DefaultValue = defaultValue; | DefaultValue = defaultValue; | ||||
| } | } | ||||
| @@ -1,6 +1,9 @@ | |||||
| using System.Collections.Immutable; | using System.Collections.Immutable; | ||||
| using System.Text; | using System.Text; | ||||
| using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
| using System.Collections.Generic; | |||||
| using System.Linq; | |||||
| using System; | |||||
| namespace Discord.Commands | namespace Discord.Commands | ||||
| { | { | ||||
| @@ -20,6 +23,7 @@ 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>(); | ||||
| bool isEscaping = false; | bool isEscaping = false; | ||||
| char c; | char c; | ||||
| @@ -70,6 +74,10 @@ 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; | ||||
| @@ -110,10 +118,32 @@ namespace Discord.Commands | |||||
| var typeReaderResult = await curParam.Parse(context, argString).ConfigureAwait(false); | var typeReaderResult = await curParam.Parse(context, argString).ConfigureAwait(false); | ||||
| if (!typeReaderResult.IsSuccess) | if (!typeReaderResult.IsSuccess) | ||||
| return ParseResult.FromError(typeReaderResult); | return ParseResult.FromError(typeReaderResult); | ||||
| argList.Add(typeReaderResult.Value); | |||||
| curParam = null; | |||||
| curPart = ParserPart.None; | |||||
| if (curParam.IsParams) | |||||
| { | |||||
| paramsList.Add(typeReaderResult.Value); | |||||
| 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); | |||||
| argList.Add(realParams); | |||||
| curParam = null; | |||||
| curPart = ParserPart.None; | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| argList.Add(typeReaderResult.Value); | |||||
| curParam = null; | |||||
| curPart = ParserPart.None; | |||||
| } | |||||
| argBuilder.Clear(); | argBuilder.Clear(); | ||||
| } | } | ||||
| } | } | ||||