Skip to content

Commit

Permalink
fix parse failure
Browse files Browse the repository at this point in the history
  • Loading branch information
neuecc committed Jun 3, 2024
1 parent afcde2b commit 96a3121
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 29 deletions.
19 changes: 15 additions & 4 deletions ReadMe.md
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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("""
Expand Down
32 changes: 15 additions & 17 deletions sandbox/GeneratorSandbox/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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}"));



Expand Down
27 changes: 19 additions & 8 deletions src/ConsoleAppFramework/Command.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System;
using System.Data.Common;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Reflection.Metadata;
using System.Text;

Expand Down Expand Up @@ -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)
Expand All @@ -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:
Expand All @@ -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
Expand All @@ -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;
Expand All @@ -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]); }}";
}
}
}
Expand Down
11 changes: 11 additions & 0 deletions src/ConsoleAppFramework/ConsoleAppGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<T>(ReadOnlySpan<string> args, ref T[] result, ref int i)
where T : IParsable<T>
{
Expand Down
14 changes: 14 additions & 0 deletions tests/ConsoleAppFramework.GeneratorTests/CSharpGeneratorRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
6 changes: 6 additions & 0 deletions tests/ConsoleAppFramework.GeneratorTests/RunTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
{
Expand Down

0 comments on commit 96a3121

Please sign in to comment.