Skip to content

Commit 1e1229a

Browse files
committed
allow more than 16 arguments #110
1 parent fe2877e commit 1e1229a

File tree

6 files changed

+256
-32
lines changed

6 files changed

+256
-32
lines changed
Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,39 @@
11
using ConsoleAppFramework;
22

3-
var app = ConsoleApp.Create();
43

5-
app.Add("aaa", () =>
6-
{
7-
});
4+
var t = new Test();
85

6+
var app = ConsoleApp.Create();
97

8+
app.Add("foo", t.Handle);
109

10+
app.Run(args);
1111

12-
app.Add("aabcdefg", int (int x, string y) =>
13-
{
14-
return default!;
15-
});
1612

17-
app.Run(args);
13+
public partial class Test
14+
{
15+
public void Handle(
16+
bool a1,
17+
bool a2,
18+
bool a3,
19+
bool a4,
20+
bool a5,
21+
bool a6,
22+
bool a7,
23+
bool a8,
24+
bool a9,
25+
bool a10,
26+
bool a11,
27+
bool a12,
28+
bool a13,
29+
bool a14,
30+
bool a15,
31+
bool a16,
32+
bool a17,
33+
bool a18,
34+
bool a19
35+
)
36+
{
37+
Console.Write("ok");
38+
}
39+
}

src/ConsoleAppFramework/Command.cs

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ public enum MethodKind
1010

1111
public enum DelegateBuildType
1212
{
13-
MakeDelegateWhenHasDefaultValue,
14-
OnlyActionFunc,
13+
MakeCustomDelegateWhenHasDefaultValueOrTooLarge,
1514
None
1615
}
1716

@@ -31,25 +30,30 @@ public record class Command
3130
public required EquatableArray<FilterInfo> Filters { get; init; }
3231
public bool HasFilter => Filters.Length != 0;
3332

34-
public string? BuildDelegateSignature(out string? delegateType)
33+
// return is delegateType(Name).
34+
public string? BuildDelegateSignature(string customDelegateTypeName, out string? customDelegateDefinition)
3535
{
36-
if (DelegateBuildType == DelegateBuildType.MakeDelegateWhenHasDefaultValue)
37-
{
38-
if (MethodKind == MethodKind.Lambda && Parameters.Any(x => x.HasDefaultValue || x.IsParams))
39-
{
40-
delegateType = BuildDelegateType("RunCommand");
41-
return "RunCommand";
42-
}
43-
}
44-
45-
delegateType = null;
36+
customDelegateDefinition = null;
4637

4738
if (DelegateBuildType == DelegateBuildType.None)
4839
{
4940
return null;
5041
}
5142

52-
if (MethodKind == MethodKind.FunctionPointer) return BuildFunctionPointerDelegateSignature();
43+
if (MethodKind == MethodKind.FunctionPointer)
44+
{
45+
customDelegateDefinition = null;
46+
return BuildFunctionPointerDelegateSignature();
47+
}
48+
49+
if (DelegateBuildType == DelegateBuildType.MakeCustomDelegateWhenHasDefaultValueOrTooLarge)
50+
{
51+
if (Parameters.Length > 16 || (MethodKind == MethodKind.Lambda && Parameters.Any(x => x.HasDefaultValue || x.IsParams)))
52+
{
53+
customDelegateDefinition = BuildDelegateTypeDefinition(customDelegateTypeName);
54+
return customDelegateTypeName;
55+
}
56+
}
5357

5458
if (IsAsync)
5559
{
@@ -126,7 +130,7 @@ public string BuildFunctionPointerDelegateSignature()
126130
return $"delegate* managed<{parameters}{comma}{retType}>";
127131
}
128132

129-
public string BuildDelegateType(string delegateName)
133+
public string BuildDelegateTypeDefinition(string delegateName)
130134
{
131135
var retType = (IsAsync, IsVoid) switch
132136
{

src/ConsoleAppFramework/ConsoleAppGenerator.cs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
4141
var reporter = new DiagnosticReporter();
4242
var node = (InvocationExpressionSyntax)context.Node;
4343
var wellknownTypes = new WellKnownTypes(context.SemanticModel.Compilation);
44-
var parser = new Parser(reporter, node, context.SemanticModel, wellknownTypes, DelegateBuildType.MakeDelegateWhenHasDefaultValue, []);
44+
var parser = new Parser(reporter, node, context.SemanticModel, wellknownTypes, DelegateBuildType.MakeCustomDelegateWhenHasDefaultValueOrTooLarge, []);
4545
var isRunAsync = (node.Expression as MemberAccessExpressionSyntax)?.Name.Identifier.Text == "RunAsync";
4646

4747
var command = parser.ParseAndValidateForRun();
@@ -624,20 +624,32 @@ static void EmitConsoleAppBuilder(SourceProductionContext sourceProductionContex
624624
var sb = new SourceBuilder(0);
625625
sb.AppendLine(GeneratedCodeHeader);
626626

627+
var delegateSignatures = new List<string>();
628+
627629
// with id number
628630
var commandIds = collectBuilderContext.Commands
629631
.Select((x, i) =>
630632
{
631-
return new Emitter.CommandWithId(
632-
FieldType: x!.BuildDelegateSignature(out _), // for builder, always generate Action/Func so ok to ignore out var.
633+
var command = new Emitter.CommandWithId(
634+
FieldType: x!.BuildDelegateSignature(Emitter.CommandWithId.BuildCustomDelegateTypeName(i), out var delegateDef),
633635
Command: x!,
634636
Id: i
635637
);
638+
if (delegateDef != null)
639+
{
640+
delegateSignatures.Add(delegateDef);
641+
}
642+
return command;
636643
})
637644
.ToArray();
638645

639646
using (sb.BeginBlock("internal static partial class ConsoleApp"))
640647
{
648+
foreach (var d in delegateSignatures)
649+
{
650+
sb.AppendLine(d);
651+
}
652+
641653
var emitter = new Emitter();
642654
emitter.EmitBuilder(sb, commandIds, hasRun, hasRunAsync);
643655
}
@@ -748,7 +760,7 @@ public CollectBuilderContext(ImmutableArray<BuilderContext> contexts, Cancellati
748760
.Select(x =>
749761
{
750762
var wellKnownTypes = new WellKnownTypes(x.Model.Compilation);
751-
var parser = new Parser(DiagnosticReporter, x.Node, x.Model, wellKnownTypes, DelegateBuildType.OnlyActionFunc, globalFilters);
763+
var parser = new Parser(DiagnosticReporter, x.Node, x.Model, wellKnownTypes, DelegateBuildType.MakeCustomDelegateWhenHasDefaultValueOrTooLarge, globalFilters);
752764
var command = parser.ParseAndValidateForBuilderDelegateRegistration();
753765

754766
// validation command name duplicate

src/ConsoleAppFramework/Emitter.cs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public void EmitRun(SourceBuilder sb, CommandWithId commandWithId, bool isRunAsy
2929
methodName = methodName ?? (isRunAsync ? "RunAsync" : "Run");
3030
var unsafeCode = (command.MethodKind == MethodKind.FunctionPointer) ? "unsafe " : "";
3131

32-
var commandMethodType = command.BuildDelegateSignature(out var delegateType);
32+
var commandMethodType = command.BuildDelegateSignature(commandWithId.BuildCustomDelegateTypeName(), out var delegateType);
3333
if (commandMethodType != null)
3434
{
3535
commandMethodType = $", {commandMethodType} command";
@@ -539,7 +539,7 @@ void EmitLeafCommand(CommandWithId? command)
539539

540540
void EmitFilterInvoker(CommandWithId command)
541541
{
542-
var commandType = command.Command.BuildDelegateSignature(out _);
542+
var commandType = command.Command.BuildDelegateSignature(command.BuildCustomDelegateTypeName(), out _);
543543
var needsCommand = commandType != null;
544544
if (needsCommand) commandType = $", {commandType} command";
545545

@@ -605,5 +605,17 @@ public void EmitHelp(SourceBuilder sb, CommandWithId[] commands)
605605
}
606606
}
607607

608-
internal record CommandWithId(string? FieldType, Command Command, int Id);
608+
internal record CommandWithId(string? FieldType, Command Command, int Id)
609+
{
610+
public static string BuildCustomDelegateTypeName(int id)
611+
{
612+
if (id < 0) return "DelegateCommand";
613+
return $"DelegateCommand{id}";
614+
}
615+
616+
public string BuildCustomDelegateTypeName()
617+
{
618+
return BuildCustomDelegateTypeName(Id);
619+
}
620+
}
609621
}
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
7+
namespace ConsoleAppFramework.GeneratorTests;
8+
9+
public class BuildCustomDelegateTest(ITestOutputHelper output)
10+
{
11+
VerifyHelper verifier = new VerifyHelper(output, "CAF");
12+
13+
[Fact]
14+
public void Run()
15+
{
16+
var code = """
17+
ConsoleApp.Run(args, (
18+
bool a1,
19+
bool a2,
20+
bool a3,
21+
bool a4,
22+
bool a5,
23+
bool a6,
24+
bool a7,
25+
bool a8,
26+
bool a9,
27+
bool a10,
28+
bool a11,
29+
bool a12,
30+
bool a13,
31+
bool a14,
32+
bool a15,
33+
bool a16 // ok it is Action
34+
) => { Console.Write("ok"); });
35+
""";
36+
37+
verifier.Execute(code, "", "ok");
38+
39+
var code2 = """
40+
ConsoleApp.Run(args, (
41+
bool a1,
42+
bool a2,
43+
bool a3,
44+
bool a4,
45+
bool a5,
46+
bool a6,
47+
bool a7,
48+
bool a8,
49+
bool a9,
50+
bool a10,
51+
bool a11,
52+
bool a12,
53+
bool a13,
54+
bool a14,
55+
bool a15,
56+
bool a16,
57+
bool a17 // custom delegate
58+
) => { Console.Write("ok"); });
59+
""";
60+
61+
verifier.Execute(code2, "", "ok");
62+
63+
64+
verifier.Execute("""
65+
var t = new Test();
66+
ConsoleApp.Run(args, t.Handle);
67+
68+
public partial class Test
69+
{
70+
public void Handle(
71+
bool a1,
72+
bool a2,
73+
bool a3,
74+
bool a4,
75+
bool a5,
76+
bool a6,
77+
bool a7,
78+
bool a8,
79+
bool a9,
80+
bool a10,
81+
bool a11,
82+
bool a12,
83+
bool a13,
84+
bool a14,
85+
bool a15,
86+
bool a16,
87+
bool a17,
88+
bool a18,
89+
bool a19
90+
)
91+
{
92+
Console.Write("ok");
93+
}
94+
}
95+
""", "", "ok");
96+
97+
98+
99+
verifier.Execute("""
100+
unsafe
101+
{
102+
ConsoleApp.Run(args, &Test.Handle);
103+
}
104+
105+
public partial class Test
106+
{
107+
public static void Handle(
108+
bool a1,
109+
bool a2,
110+
bool a3,
111+
bool a4,
112+
bool a5,
113+
bool a6,
114+
bool a7,
115+
bool a8,
116+
bool a9,
117+
bool a10,
118+
bool a11,
119+
bool a12,
120+
bool a13,
121+
bool a14,
122+
bool a15,
123+
bool a16,
124+
bool a17,
125+
bool a18,
126+
bool a19
127+
)
128+
{
129+
Console.Write("ok");
130+
}
131+
}
132+
""", "", "ok");
133+
}
134+
135+
[Fact]
136+
public void Builder()
137+
{
138+
verifier.Execute("""
139+
var t = new Test();
140+
141+
var app = ConsoleApp.Create();
142+
app.Add("", t.Handle);
143+
app.Run(args);
144+
145+
public partial class Test
146+
{
147+
public void Handle(
148+
bool a1,
149+
bool a2,
150+
bool a3,
151+
bool a4,
152+
bool a5,
153+
bool a6,
154+
bool a7,
155+
bool a8,
156+
bool a9,
157+
bool a10,
158+
bool a11,
159+
bool a12,
160+
bool a13,
161+
bool a14,
162+
bool a15,
163+
bool a16,
164+
bool a17,
165+
bool a18,
166+
bool a19
167+
)
168+
{
169+
Console.Write("ok");
170+
}
171+
}
172+
""", "", "ok");
173+
}
174+
}

tests/ConsoleAppFramework.GeneratorTests/CSharpGeneratorRunner.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public static void InitializeCompilation()
2929
var compilation = CSharpCompilation.Create("generatortest",
3030
references: references,
3131
syntaxTrees: [CSharpSyntaxTree.ParseText(globalUsings, path: "GlobalUsings.cs")],
32-
options: new CSharpCompilationOptions(OutputKind.ConsoleApplication)); // .exe
32+
options: new CSharpCompilationOptions(OutputKind.ConsoleApplication, allowUnsafe: true)); // .exe
3333

3434
baseCompilation = compilation;
3535
}

0 commit comments

Comments
 (0)