From c8fc0ffa334c4e11c768433ed1da68c56976d372 Mon Sep 17 00:00:00 2001 From: Finite Reality Date: Sat, 30 Jul 2016 21:37:55 +0100 Subject: [PATCH] Add support for 'params' arguments --- src/Discord.Net.Commands/Command.cs | 21 ++++++++++-- src/Discord.Net.Commands/CommandParameter.cs | 6 +++- src/Discord.Net.Commands/CommandParser.cs | 36 ++++++++++++++++++-- 3 files changed, 56 insertions(+), 7 deletions(-) diff --git a/src/Discord.Net.Commands/Command.cs b/src/Discord.Net.Commands/Command.cs index f62d6c928..3ae2c5597 100644 --- a/src/Discord.Net.Commands/Command.cs +++ b/src/Discord.Net.Commands/Command.cs @@ -71,6 +71,7 @@ namespace Discord.Commands { var parameter = parameters[i]; var type = parameter.ParameterType; + Type underlyingType = null; if (i == 0) { @@ -80,10 +81,24 @@ namespace Discord.Commands continue; } - var typeInfo = type.GetTypeInfo(); 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); Module.Service.AddTypeReader(type, reader); @@ -101,7 +116,7 @@ namespace Discord.Commands bool isOptional = parameter.IsOptional; 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(); } diff --git a/src/Discord.Net.Commands/CommandParameter.cs b/src/Discord.Net.Commands/CommandParameter.cs index ef8fa8533..2be39bbf5 100644 --- a/src/Discord.Net.Commands/CommandParameter.cs +++ b/src/Discord.Net.Commands/CommandParameter.cs @@ -15,17 +15,21 @@ namespace Discord.Commands public string Description { get; } public bool IsOptional { get; } public bool IsRemainder { get; } + public bool IsParams { get; } public Type Type { get; } + public Type UnderlyingType { 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; Description = description; Type = type; + UnderlyingType = underlyingType; _reader = reader; IsOptional = isOptional; IsRemainder = isRemainder; + IsParams = isParams; DefaultValue = defaultValue; } diff --git a/src/Discord.Net.Commands/CommandParser.cs b/src/Discord.Net.Commands/CommandParser.cs index 27a5194c5..e9af0ce44 100644 --- a/src/Discord.Net.Commands/CommandParser.cs +++ b/src/Discord.Net.Commands/CommandParser.cs @@ -1,6 +1,9 @@ using System.Collections.Immutable; using System.Text; using System.Threading.Tasks; +using System.Collections.Generic; +using System.Linq; +using System; namespace Discord.Commands { @@ -20,6 +23,7 @@ namespace Discord.Commands int endPos = input.Length; var curPart = ParserPart.None; int lastArgEndPos = int.MinValue; + IList paramsList = null; // TODO: could we use a better type? var argList = ImmutableArray.CreateBuilder(); bool isEscaping = false; char c; @@ -70,6 +74,10 @@ namespace Discord.Commands argBuilder.Append(c); continue; } + if (curParam != null && curParam.IsParams) + { + paramsList = new List(); + } if (c == '\"') { curPart = ParserPart.QuotedParameter; @@ -110,10 +118,32 @@ namespace Discord.Commands var typeReaderResult = await curParam.Parse(context, argString).ConfigureAwait(false); if (!typeReaderResult.IsSuccess) 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(); } }