public static (string filename, string source) Emit(UnionTypeSchema unionTypeSchema, Action <Diagnostic> reportDiagnostic, CancellationToken cancellationToken) { var builder = new CSharpBuilder(); builder.WriteUsings("System", "System.Threading.Tasks"); using (builder.Namespace(unionTypeSchema.Namespace)) { using (builder.PublicStaticPartialClass("MatchExtension")) { GenerateMatchMethod(builder, unionTypeSchema, "T"); builder.WriteLine(""); GenerateMatchMethod(builder, unionTypeSchema, "Task<T>"); builder.WriteLine(""); var thisParameter = ThisParameter(unionTypeSchema, $"Task<{unionTypeSchema.TypeName}>"); WriteMatchSignature(builder, unionTypeSchema, thisParameter, "Task<T>", "T", "public static async"); var caseParameters = unionTypeSchema.Cases.Select(c => c.ParameterName).ToSeparatedString(); builder.WriteLine($"(await {thisParameter.Name}.ConfigureAwait(false)).Match({caseParameters});"); builder.WriteLine(""); var thisParameter1 = ThisParameter(unionTypeSchema, $"Task<{unionTypeSchema.TypeName}>"); WriteMatchSignature(builder, unionTypeSchema, thisParameter1, "Task<T>", handlerReturnType: "Task<T>", "public static async"); builder.WriteLine($"await (await {thisParameter1.Name}.ConfigureAwait(false)).Match({caseParameters}).ConfigureAwait(false);"); } } return($"{unionTypeSchema.TypeName}MatchExtension.g.cs", builder.ToString()); }
static void GenerateMatchMethod(CSharpBuilder builder, UnionTypeSchema unionTypeSchema, string t) { var thisParameterType = unionTypeSchema.TypeName; var thisParameter = ThisParameter(unionTypeSchema, thisParameterType); var thisParameterName = thisParameter.Name; WriteMatchSignature(builder, unionTypeSchema, thisParameter, t); builder.WriteLine($"{thisParameterName} switch"); using (builder.ScopeWithSemicolon()) { var caseIndex = 0; foreach (var c in unionTypeSchema.Cases) { caseIndex++; builder.WriteLine($"{c.FullTypeName} case{caseIndex} => {c.ParameterName}(case{caseIndex}),"); } builder.WriteLine( $"_ => throw new ArgumentException($\"Unknown type derived from {unionTypeSchema.TypeName}: {{{thisParameterName}.GetType().Name}}\")"); } }
static Parameter ThisParameter(UnionTypeSchema unionTypeSchema, string thisParameterType) => new($"this {thisParameterType}", unionTypeSchema.TypeName.ToParameterName());