From 96a3121f3143071a7a38351212844e44a9159d00 Mon Sep 17 00:00:00 2001 From: neuecc Date: Mon, 3 Jun 2024 09:12:25 +0900 Subject: [PATCH] fix parse failure --- ReadMe.md | 19 ++++++++--- sandbox/GeneratorSandbox/Program.cs | 32 +++++++++---------- src/ConsoleAppFramework/Command.cs | 27 +++++++++++----- .../ConsoleAppGenerator.cs | 11 +++++++ .../CSharpGeneratorRunner.cs | 14 ++++++++ .../RunTest.cs | 6 ++++ 6 files changed, 80 insertions(+), 29 deletions(-) diff --git a/ReadMe.md b/ReadMe.md index 3a3662f..133e645 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -42,26 +42,26 @@ internal static partial class ConsoleApp { case "--foo": { - if (!int.TryParse(args[++i], out arg0)) { ThrowArgumentParseFailed("foo", args[i]); } + if (!TryIncrementIndex(ref i, args.Length) || !int.TryParse(args[i], out arg0)) { ThrowArgumentParseFailed("foo", args[i]); } arg0Parsed = true; break; } case "--bar": { - if (!int.TryParse(args[++i], out arg1)) { ThrowArgumentParseFailed("bar", args[i]); } + if (!TryIncrementIndex(ref i, args.Length) || !int.TryParse(args[i], out arg1)) { ThrowArgumentParseFailed("bar", args[i]); } arg1Parsed = true; break; } default: if (string.Equals(name, "--foo", StringComparison.OrdinalIgnoreCase)) { - if (!int.TryParse(args[++i], out arg0)) { ThrowArgumentParseFailed("foo", args[i]); } + if (!TryIncrementIndex(ref i, args.Length) || !int.TryParse(args[i], out arg0)) { ThrowArgumentParseFailed("foo", args[i]); } arg0Parsed = true; break; } if (string.Equals(name, "--bar", StringComparison.OrdinalIgnoreCase)) { - if (!int.TryParse(args[++i], out arg1)) { ThrowArgumentParseFailed("bar", args[i]); } + if (!TryIncrementIndex(ref i, args.Length) || !int.TryParse(args[i], out arg1)) { ThrowArgumentParseFailed("bar", args[i]); } arg1Parsed = true; break; } @@ -88,6 +88,17 @@ internal static partial class ConsoleApp } } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static bool TryIncrementIndex(ref int index, int length) + { + if (index < length) + { + index++; + return true; + } + return false; + } + static partial void ShowHelp(int helpId) { Log(""" diff --git a/sandbox/GeneratorSandbox/Program.cs b/sandbox/GeneratorSandbox/Program.cs index d782802..35b3c68 100644 --- a/sandbox/GeneratorSandbox/Program.cs +++ b/sandbox/GeneratorSandbox/Program.cs @@ -11,29 +11,27 @@ using ZLogger; -args = "--first-arg invalid.email --second-arg 10".Split(' '); +//args = "--first-arg invalid.email --second-arg 10".Split(' '); -ConsoleApp.Timeout = Timeout.InfiniteTimeSpan; +//ConsoleApp.Timeout = Timeout.InfiniteTimeSpan; -ConsoleApp.Run(args, ( - [Argument] DateTime dateTime, // Argument - [Argument] Guid guidvalue, // - int intVar, // required - bool boolFlag, // flag - MyEnum enumValue, // enum - int[] array, // array - MyClass obj, // object - string optional = "abcde", // optional - double? nullableValue = null, // nullable - params string[] paramsArray // params - ) => { }); - - - +//ConsoleApp.Run(args, ( +// [Argument] DateTime dateTime, // Argument +// [Argument] Guid guidvalue, // +// int intVar, // required +// bool boolFlag, // flag +// MyEnum enumValue, // enum +// int[] array, // array +// MyClass obj, // object +// string optional = "abcde", // optional +// double? nullableValue = null, // nullable +// params string[] paramsArray // params +// ) => { }); +ConsoleApp.Run(args, (int foo, int bar) => Console.WriteLine($"Sum: {foo + bar}")); diff --git a/src/ConsoleAppFramework/Command.cs b/src/ConsoleAppFramework/Command.cs index 94a26e0..ecb8e4e 100644 --- a/src/ConsoleAppFramework/Command.cs +++ b/src/ConsoleAppFramework/Command.cs @@ -2,6 +2,7 @@ using System; using System.Data.Common; using System.Diagnostics.CodeAnalysis; +using System.Reflection; using System.Reflection.Metadata; using System.Text; @@ -168,9 +169,10 @@ public record class CommandParameter public required string Description { get; init; } public bool RequireCheckArgumentParsed => !(HasDefaultValue || IsParams || IsFlag); + // increment = false when passed from [Argument] public string BuildParseMethod(int argCount, string argumentName, WellKnownTypes wellKnownTypes, bool increment) { - var index = increment ? "++i" : "i"; + var incrementIndex = increment ? "!TryIncrementIndex(ref i, args.Length) || " : ""; return Core(Type, false); string Core(ITypeSymbol type, bool nullable) @@ -190,13 +192,22 @@ string Core(ITypeSymbol type, bool nullable) if (CustomParserType != null) { - return $"if (!{CustomParserType.ToFullyQualifiedFormatDisplayString()}.TryParse(args[{index}], {outArgVar})) {{ ThrowArgumentParseFailed(\"{argumentName}\", args[i]); }}{elseExpr}"; + return $"if ({incrementIndex}!{CustomParserType.ToFullyQualifiedFormatDisplayString()}.TryParse(args[i], {outArgVar})) {{ ThrowArgumentParseFailed(\"{argumentName}\", args[i]); }}{elseExpr}"; } switch (type.SpecialType) { case SpecialType.System_String: - return $"arg{argCount} = args[{index}];"; // no parse + // no parse + if (increment) + { + return $"if (!TryIncrementIndex(ref i, args.Length)) {{ ThrowArgumentParseFailed(\"{argumentName}\", args[i]); }} else {{ arg{argCount} = args[i]; }}"; + } + else + { + return $"arg{argCount} = args[i];"; + } + case SpecialType.System_Boolean: return $"arg{argCount} = true;"; // bool is true flag case SpecialType.System_Char: @@ -218,7 +229,7 @@ string Core(ITypeSymbol type, bool nullable) // Enum if (type.TypeKind == TypeKind.Enum) { - return $"if (!Enum.TryParse<{type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)}>(args[{index}], true, {outArgVar})) {{ ThrowArgumentParseFailed(\"{argumentName}\", args[i]); }}{elseExpr}"; + return $"if ({incrementIndex}!Enum.TryParse<{type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)}>(args[i], true, {outArgVar})) {{ ThrowArgumentParseFailed(\"{argumentName}\", args[i]); }}{elseExpr}"; } // ParamsArray @@ -236,7 +247,7 @@ string Core(ITypeSymbol type, bool nullable) { if (elementType.AllInterfaces.Any(x => x.EqualsUnconstructedGenericType(parsable))) { - return $"if (!TrySplitParse(args[{index}], {outArgVar})) {{ ThrowArgumentParseFailed(\"{argumentName}\", args[i]); }}{elseExpr}"; + return $"if ({incrementIndex}!TrySplitParse(args[i], {outArgVar})) {{ ThrowArgumentParseFailed(\"{argumentName}\", args[i]); }}{elseExpr}"; } } break; @@ -260,15 +271,15 @@ string Core(ITypeSymbol type, bool nullable) if (tryParseKnownPrimitive) { - return $"if (!{type.ToFullyQualifiedFormatDisplayString()}.TryParse(args[{index}], {outArgVar})) {{ ThrowArgumentParseFailed(\"{argumentName}\", args[i]); }}{elseExpr}"; + return $"if ({incrementIndex}!{type.ToFullyQualifiedFormatDisplayString()}.TryParse(args[i], {outArgVar})) {{ ThrowArgumentParseFailed(\"{argumentName}\", args[i]); }}{elseExpr}"; } else if (tryParseIParsable) { - return $"if (!{type.ToFullyQualifiedFormatDisplayString()}.TryParse(args[{index}], null, {outArgVar})) {{ ThrowArgumentParseFailed(\"{argumentName}\", args[i]); }}{elseExpr}"; + return $"if ({incrementIndex}!{type.ToFullyQualifiedFormatDisplayString()}.TryParse(args[i], null, {outArgVar})) {{ ThrowArgumentParseFailed(\"{argumentName}\", args[i]); }}{elseExpr}"; } else { - return $"try {{ arg{argCount} = System.Text.Json.JsonSerializer.Deserialize<{type.ToFullyQualifiedFormatDisplayString()}>(args[{index}]); }} catch {{ ThrowArgumentParseFailed(\"{argumentName}\", args[i]); }}"; + return $"try {{ arg{argCount} = System.Text.Json.JsonSerializer.Deserialize<{type.ToFullyQualifiedFormatDisplayString()}>(args[{(increment ? "++i" : "i")}]); }} catch {{ ThrowArgumentParseFailed(\"{argumentName}\", args[i]); }}"; } } } diff --git a/src/ConsoleAppFramework/ConsoleAppGenerator.cs b/src/ConsoleAppFramework/ConsoleAppGenerator.cs index 3c12336..a1210fb 100644 --- a/src/ConsoleAppFramework/ConsoleAppGenerator.cs +++ b/src/ConsoleAppFramework/ConsoleAppGenerator.cs @@ -188,6 +188,17 @@ static void ThrowArgumentNameNotFound(string argumentName) throw new ArgumentException($"Argument '{argumentName}' does not found in command prameters."); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static bool TryIncrementIndex(ref int index, int length) + { + if ((index + 1) < length) + { + index += 1; + return true; + } + return false; + } + static bool TryParseParamsArray(ReadOnlySpan args, ref T[] result, ref int i) where T : IParsable { diff --git a/tests/ConsoleAppFramework.GeneratorTests/CSharpGeneratorRunner.cs b/tests/ConsoleAppFramework.GeneratorTests/CSharpGeneratorRunner.cs index b523a11..57a7b89 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/CSharpGeneratorRunner.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/CSharpGeneratorRunner.cs @@ -150,6 +150,20 @@ public void Execute(string code, string args, string expected, [CallerArgumentEx stdout.Should().Be(expected); } + public string Error(string code, string args, [CallerArgumentExpression("code")] string? codeExpr = null) + { + output.WriteLine(codeExpr); + + var (compilation, diagnostics, stdout) = CSharpGeneratorRunner.CompileAndExecute(code, args == "" ? [] : args.Split(' ')); + foreach (var item in diagnostics) + { + output.WriteLine(item.ToString()); + } + OutputGeneratedCode(compilation); + + return stdout; + } + string GetLocationText(Diagnostic diagnostic) { var location = diagnostic.Location; diff --git a/tests/ConsoleAppFramework.GeneratorTests/RunTest.cs b/tests/ConsoleAppFramework.GeneratorTests/RunTest.cs index 53860ac..8ca8234 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/RunTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/RunTest.cs @@ -20,6 +20,12 @@ public void SyncRun() verifier.Execute("ConsoleApp.Run(args, (int x, int y) => { Console.Write((x + y)); });", "--x 10 --y 20", "30"); } + [Fact] + public void SyncRunShouldFailed() + { + verifier.Error("ConsoleApp.Run(args, (int x) => { Console.Write((x)); });", "--x").Should().Contain("Argument 'x' parse failed."); + } + [Fact] public void ValidateOne() {