From 3755a027b3ccfb404977ba6020ce9e394f3f56f4 Mon Sep 17 00:00:00 2001 From: Adam Gauthier Date: Sun, 8 Sep 2019 18:06:19 -0400 Subject: [PATCH] feature: Provide ParameterInfo with error ParseResult (#1355) Currently, when handling parsing errors, there is no way to know what parameter caused the error. This change makes the CommandParser create the parsing error with the current parameter info when ParseAsync() fails. It is then available through the ErrorParameter of the ParseResult. --- src/Discord.Net.Commands/CommandParser.cs | 12 ++++---- .../Results/ParseResult.cs | 30 ++++++++++++++----- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/Discord.Net.Commands/CommandParser.cs b/src/Discord.Net.Commands/CommandParser.cs index c77b56042..88698cda5 100644 --- a/src/Discord.Net.Commands/CommandParser.cs +++ b/src/Discord.Net.Commands/CommandParser.cs @@ -103,7 +103,7 @@ namespace Discord.Commands argBuilder.Append(c); continue; } - + if (IsOpenQuote(aliasMap, c)) { curPart = ParserPart.QuotedParameter; @@ -136,7 +136,7 @@ namespace Discord.Commands else argBuilder.Append(c); } - + if (argString != null) { if (curParam == null) @@ -149,7 +149,7 @@ namespace Discord.Commands var typeReaderResult = await curParam.ParseAsync(context, argString, services).ConfigureAwait(false); if (!typeReaderResult.IsSuccess && typeReaderResult.Error != CommandError.MultipleMatches) - return ParseResult.FromError(typeReaderResult); + return ParseResult.FromError(typeReaderResult, curParam); if (curParam.IsMultiple) { @@ -172,7 +172,7 @@ namespace Discord.Commands { var typeReaderResult = await curParam.ParseAsync(context, argBuilder.ToString(), services).ConfigureAwait(false); if (!typeReaderResult.IsSuccess) - return ParseResult.FromError(typeReaderResult); + return ParseResult.FromError(typeReaderResult, curParam); argList.Add(typeReaderResult); } @@ -180,7 +180,7 @@ namespace Discord.Commands 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."); - + //Add missing optionals for (int i = argList.Count; i < command.Parameters.Count; i++) { @@ -191,7 +191,7 @@ namespace Discord.Commands return ParseResult.FromError(CommandError.BadArgCount, "The input text has too few parameters."); argList.Add(TypeReaderResult.FromSuccess(param.DefaultValue)); } - + return ParseResult.FromSuccess(argList.ToImmutable(), paramList.ToImmutable()); } } diff --git a/src/Discord.Net.Commands/Results/ParseResult.cs b/src/Discord.Net.Commands/Results/ParseResult.cs index 8e10dc66c..43351b6bf 100644 --- a/src/Discord.Net.Commands/Results/ParseResult.cs +++ b/src/Discord.Net.Commands/Results/ParseResult.cs @@ -18,30 +18,40 @@ namespace Discord.Commands /// public string ErrorReason { get; } + /// + /// Provides information about the parameter that caused the parsing error. + /// + /// + /// A indicating the parameter info of the error that may have occurred during parsing; + /// null if the parsing was successful or the parsing error is not specific to a single parameter. + /// + public ParameterInfo ErrorParameter { get; } + /// public bool IsSuccess => !Error.HasValue; - private ParseResult(IReadOnlyList argValues, IReadOnlyList paramValues, CommandError? error, string errorReason) + private ParseResult(IReadOnlyList argValues, IReadOnlyList paramValues, CommandError? error, string errorReason, ParameterInfo errorParamInfo) { ArgValues = argValues; ParamValues = paramValues; Error = error; ErrorReason = errorReason; + ErrorParameter = errorParamInfo; } - + public static ParseResult FromSuccess(IReadOnlyList argValues, IReadOnlyList paramValues) { for (int i = 0; i < argValues.Count; i++) { if (argValues[i].Values.Count > 1) - return new ParseResult(argValues, paramValues, CommandError.MultipleMatches, "Multiple matches found."); + return new ParseResult(argValues, paramValues, CommandError.MultipleMatches, "Multiple matches found.", null); } for (int i = 0; i < paramValues.Count; i++) { if (paramValues[i].Values.Count > 1) - return new ParseResult(argValues, paramValues, CommandError.MultipleMatches, "Multiple matches found."); + return new ParseResult(argValues, paramValues, CommandError.MultipleMatches, "Multiple matches found.", null); } - return new ParseResult(argValues, paramValues, null, null); + return new ParseResult(argValues, paramValues, null, null, null); } public static ParseResult FromSuccess(IReadOnlyList argValues, IReadOnlyList paramValues) { @@ -55,15 +65,19 @@ namespace Discord.Commands for (int i = 0; i < paramValues.Count; i++) paramList[i] = TypeReaderResult.FromSuccess(paramValues[i]); } - return new ParseResult(argList, paramList, null, null); + return new ParseResult(argList, paramList, null, null, null); } public static ParseResult FromError(CommandError error, string reason) - => new ParseResult(null, null, error, reason); + => new ParseResult(null, null, error, reason, null); + public static ParseResult FromError(CommandError error, string reason, ParameterInfo parameterInfo) + => new ParseResult(null, null, error, reason, parameterInfo); public static ParseResult FromError(Exception ex) => FromError(CommandError.Exception, ex.Message); public static ParseResult FromError(IResult result) - => new ParseResult(null, null, result.Error, result.ErrorReason); + => new ParseResult(null, null, result.Error, result.ErrorReason, null); + public static ParseResult FromError(IResult result, ParameterInfo parameterInfo) + => new ParseResult(null, null, result.Error, result.ErrorReason, parameterInfo); public override string ToString() => IsSuccess ? "Success" : $"{Error}: {ErrorReason}"; private string DebuggerDisplay => IsSuccess ? $"Success ({ArgValues.Count}{(ParamValues.Count > 0 ? $" +{ParamValues.Count} Values" : "")})" : $"{Error}: {ErrorReason}";