diff --git a/Funzo.SourceGenerators/Funzo.SourceGenerators.csproj b/Funzo.SourceGenerators/Funzo.SourceGenerators.csproj
index d57cc3c..2c6231a 100644
--- a/Funzo.SourceGenerators/Funzo.SourceGenerators.csproj
+++ b/Funzo.SourceGenerators/Funzo.SourceGenerators.csproj
@@ -18,13 +18,26 @@
LICENSE
true
+ true
-
-
+
+
+
+ $(GetTargetPathDependsOn);GetDependencyTargetPaths
+
+
+
+
+
+
+
+
+
+
True
diff --git a/Funzo.SourceGenerators/Generators/ResultSourceGenerator.cs b/Funzo.SourceGenerators/Generators/ResultSourceGenerator.cs
index 018f1c7..81467c4 100644
--- a/Funzo.SourceGenerators/Generators/ResultSourceGenerator.cs
+++ b/Funzo.SourceGenerators/Generators/ResultSourceGenerator.cs
@@ -3,10 +3,9 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
-using System;
+using Sorse;
using System.Collections.Immutable;
using System.Linq;
-using System.Text;
namespace Funzo.SourceGenerators.Generators;
@@ -21,40 +20,16 @@ internal class ResultSourceGenerator : GeneratorBase
var is1ArityResult = type.AttributeTypeArguments.Length == 1;
+
ResultGenerator generator = is1ArityResult
? new Result1AritySourceGenerator(type)
: new Result2AritySourceGenerator(type);
- var sb = new StringBuilder();
- sb.AppendLine($@"//
-
-namespace {type.Symbol.ContainingNamespace.ToDisplayString()}
-{{");
+ var sorse = WithSorse.CreateNamespaceScope(type.Symbol.ContainingNamespace.ToDisplayString(), []);
- // Add all needed upper classes
- foreach (var containingType in type.ContainerClasses)
- {
- var isStatic = type.Symbol.ContainingType!.IsStatic ? "static " : "";
-
- sb.AppendLine($"{isStatic}partial class {containingType.Name} {{");
- }
+ sorse.AddClassWithInnerClasses(type, generator.GenerateResult);
- sb.AppendLine($@"
- {generator.ClassDefinition}
- {{
- {generator.OkConstructor}
- {generator.OkStaticHelper}
- {generator.OkImplicitConverter}
- {generator.ErrConstructor}
- {generator.ErrStaticHelper}
- {generator.ErrImplicitConverter}
- }}
-}}");
-
- // Close all the braces opened for parent classes
- sb.AppendLine(new string('}', type.ContainerClasses.Count));
-
- var src = sb.ToString();
+ var src = sorse.GetSource();
return src;
}
diff --git a/Funzo.SourceGenerators/Generators/Results/Result1AritySourceGenerator.cs b/Funzo.SourceGenerators/Generators/Results/Result1AritySourceGenerator.cs
index 8c1ae78..52acd71 100644
--- a/Funzo.SourceGenerators/Generators/Results/Result1AritySourceGenerator.cs
+++ b/Funzo.SourceGenerators/Generators/Results/Result1AritySourceGenerator.cs
@@ -1,43 +1,38 @@
using Funzo.SourceGenerators.Helpers;
using Microsoft.CodeAnalysis;
-using System.Text;
+using Sorse.BuilderInterfaces;
namespace Funzo.SourceGenerators.Generators.Results;
+
internal class Result1AritySourceGenerator : ResultGenerator
{
internal Result1AritySourceGenerator(MarkedType symbolWithAttribute) : base(symbolWithAttribute)
{
}
- internal override string ClassDefinition => $@"partial class {ClassName} : global::Funzo.ResultBase<{ClassName},{ErrDisplayName}>, global::Funzo.IResultBase <{ClassName},{ErrDisplayName}>";
-
- internal override string OkConstructor => @$"protected {ClassName}() : base() {{}}";
-
- internal override string ErrConstructor => $@"protected {ClassName}({ErrDisplayName} _) : base(_) {{}}";
-
- internal override string OkStaticHelper => $@"public static {ClassName} Ok() => new();";
-
- internal override string ErrStaticHelper => $@"public static {ClassName} Err({ErrDisplayName} err) => new(err);";
-
- internal override string OkImplicitConverter => string.Empty;
+ protected override void GenerateResultInner(IClassBuilder builder)
+ {
+ builder.Inherits($"global::Funzo.ResultBase<{ClassName}, {ErrDisplayName}>")
+ .Implements($"global::Funzo.IResultBase<{ClassName}, {ErrDisplayName}>")
+ .WithConstructor(c => c.WithBaseCall([]))
+ .WithConstructor(c => c.WithArguments([new(new(ErrType), "x")]).WithBaseCall(["x"]))
+ .WithMethod(ClassName, "Ok", m => m.Static().WithBody(" => new();"))
+ .WithMethod(ClassName, "Err", m => m.Static().WithArguments([new(new(ErrType), "x")]).WithBody(" => new(x);"))
+ .WithImplicitConversionOperatorFrom(new(ErrType), " => new(x);");
+
+ AddConversionsForErrUnions(builder);
+ }
- internal override string ErrImplicitConverter
+ private void AddConversionsForErrUnions(IClassBuilder builder)
{
- get
+ foreach (var type in GetTypesNeedingImplicitConversions(ErrType, ResultParameterType.Err))
{
- var implicitConversions = new StringBuilder();
- implicitConversions.AppendLine($@"public static implicit operator {ClassName}({ErrDisplayName} _) => new {ClassName}(_);");
-
- if (TryGetImplicitConvertersForUnionType(ErrType, ResultParameterType.Err, out var converters))
- {
- implicitConversions.AppendLine(converters);
- }
-
- return implicitConversions.ToString();
+ builder.WithImplicitConversionOperatorFrom(new(type), $" => new(x);");
}
}
private string ErrDisplayName => ErrType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
private ITypeSymbol ErrType => TypeArguments[0];
+
}
diff --git a/Funzo.SourceGenerators/Generators/Results/Result2AritySourceGenerator.cs b/Funzo.SourceGenerators/Generators/Results/Result2AritySourceGenerator.cs
index 31f294e..508c6a4 100644
--- a/Funzo.SourceGenerators/Generators/Results/Result2AritySourceGenerator.cs
+++ b/Funzo.SourceGenerators/Generators/Results/Result2AritySourceGenerator.cs
@@ -1,55 +1,52 @@
using Funzo.SourceGenerators.Helpers;
using Microsoft.CodeAnalysis;
+using Sorse;
+using Sorse.BuilderInterfaces;
using System.Collections.Immutable;
using System.Linq;
-using System.Text;
namespace Funzo.SourceGenerators.Generators.Results;
+
internal class Result2AritySourceGenerator : ResultGenerator
{
internal Result2AritySourceGenerator(MarkedType symbolWithAttribute) : base(symbolWithAttribute)
{
}
- internal override string ClassDefinition => $@"partial class {ClassName} : global::Funzo.ResultBase<{ClassName}, {OkDisplayName},{ErrDisplayName}>, global::Funzo.IResultBase<{ClassName}, {OkDisplayName},{ErrDisplayName}>";
-
- internal override string OkConstructor => @$"protected {ClassName}({OkDisplayName} _) : base(_) {{}}";
-
- internal override string ErrConstructor => $@"protected {ClassName}({ErrDisplayName} _) : base(_) {{}}";
-
- internal override string OkStaticHelper => $@"public static {ClassName} Ok({OkDisplayName} ok) => new(ok);";
-
- internal override string ErrStaticHelper => $@"public static {ClassName} Err({ErrDisplayName} err) => new(err);";
+ protected override void GenerateResultInner(IClassBuilder builder)
+ {
+ builder.Inherits($"global::Funzo.ResultBase<{ClassName}, {OkDisplayName}, {ErrDisplayName}>")
+ .Implements($"global::Funzo.IResultBase<{ClassName}, {OkDisplayName}, {ErrDisplayName}>")
+ .WithConstructor(c => c.WithAccessModifier(AccessModifier.Protected)
+ .WithArguments([new(new(OkType), "_")]).WithBaseCall(["_"]))
+ .WithConstructor(c => c.WithAccessModifier(AccessModifier.Protected)
+ .WithArguments([new(new(ErrType), "_")]).WithBaseCall(["_"]))
+ .WithMethod(ClassName, "Ok", m => m.Static().WithArguments([new(new(OkType), "ok")]).WithBody(" => new(ok);"))
+ .WithMethod(ClassName, "Err", m => m.Static().WithArguments([new(new(ErrType), "err")]).WithBody(" => new(err);"))
+ .WithImplicitConversionOperatorFrom(new(OkType), " => new(x);")
+ .WithImplicitConversionOperatorFrom(new(ErrType), " => new(x);");
+
+ AddConversionsForUnions(builder);
+ }
- internal override string OkImplicitConverter
+ private void AddConversionsForUnions(IClassBuilder builder)
{
- get
+ if (HasCollidingParameters())
{
- var implicitConversions = new StringBuilder();
- implicitConversions.AppendLine($@"public static implicit operator {ClassName}({OkDisplayName} _) => new {ClassName}(_);");
+ return;
+ }
- if (!HasCollidingParameters() && TryGetImplicitConvertersForUnionType(OkType, ResultParameterType.Ok, out var converters))
- {
- implicitConversions.AppendLine(converters);
- }
+ var okUnions = GetTypesNeedingImplicitConversions(OkType, ResultParameterType.Ok);
+ var errUnions = GetTypesNeedingImplicitConversions(ErrType, ResultParameterType.Err);
- return implicitConversions.ToString();
+ foreach (var ok in okUnions)
+ {
+ builder.WithImplicitConversionOperatorFrom(new(ok), " => new(x);");
}
- }
- internal override string ErrImplicitConverter
- {
- get
+ foreach (var err in errUnions)
{
- var implicitConversions = new StringBuilder();
- implicitConversions.AppendLine($@"public static implicit operator {ClassName}({ErrDisplayName} _) => new {ClassName}(_);");
-
- if (!HasCollidingParameters() && TryGetImplicitConvertersForUnionType(ErrType, ResultParameterType.Err, out var converters))
- {
- implicitConversions.AppendLine(converters);
- }
-
- return implicitConversions.ToString();
+ builder.WithImplicitConversionOperatorFrom(new(err), " => new(x);");
}
}
diff --git a/Funzo.SourceGenerators/Generators/Results/ResultGenerator.cs b/Funzo.SourceGenerators/Generators/Results/ResultGenerator.cs
index bcfb446..7b23b93 100644
--- a/Funzo.SourceGenerators/Generators/Results/ResultGenerator.cs
+++ b/Funzo.SourceGenerators/Generators/Results/ResultGenerator.cs
@@ -1,8 +1,8 @@
using Funzo.SourceGenerators.Helpers;
using Microsoft.CodeAnalysis;
+using Sorse.BuilderInterfaces;
using System.Collections.Generic;
using System.Collections.Immutable;
-using System.Text;
namespace Funzo.SourceGenerators.Generators.Results;
@@ -17,14 +17,14 @@ protected ResultGenerator(MarkedType symbolWithAttribute)
_symbolWithAttribute = symbolWithAttribute;
}
- internal abstract string ClassDefinition { get; }
- internal abstract string OkConstructor { get; }
- internal abstract string ErrConstructor { get; }
- internal abstract string OkStaticHelper { get; }
- internal abstract string ErrStaticHelper { get; }
- internal abstract string OkImplicitConverter { get; }
- internal abstract string ErrImplicitConverter { get; }
+ internal void GenerateResult(IClassBuilder builder)
+ {
+ builder.Partial();
+
+ GenerateResultInner(builder);
+ }
+ protected abstract void GenerateResultInner(IClassBuilder builder);
protected string ClassName => $"{ClassSymbol.Name}";
protected bool TryGetUnionTypes(ITypeSymbol type, out IEnumerable types)
@@ -43,24 +43,13 @@ protected bool TryGetUnionTypes(ITypeSymbol type, out IEnumerable t
}
}
- protected bool TryGetImplicitConvertersForUnionType(ITypeSymbol type, ResultParameterType parameterType, out string converters)
+ protected IEnumerable GetTypesNeedingImplicitConversions(ITypeSymbol type, ResultParameterType parameterType)
{
if (!TryGetUnionTypes(type, out var unionTypes))
{
- converters = string.Empty;
- return false;
- }
-
- var sb = new StringBuilder();
-
- var ctor = parameterType is ResultParameterType.Ok ? "Ok" : "Err";
-
- foreach (var unionType in unionTypes)
- {
- sb.AppendLine($@"public static implicit operator {ClassName}({unionType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)} _) => {ctor}(_);");
+ return [];
}
- converters = sb.ToString();
- return true;
+ return unionTypes;
}
}
diff --git a/Funzo.SourceGenerators/Generators/Unions/UnionGenerator.cs b/Funzo.SourceGenerators/Generators/Unions/UnionGenerator.cs
index 054b3e4..6564dab 100644
--- a/Funzo.SourceGenerators/Generators/Unions/UnionGenerator.cs
+++ b/Funzo.SourceGenerators/Generators/Unions/UnionGenerator.cs
@@ -2,10 +2,11 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Sorse;
+using Sorse.BuilderInterfaces;
using System;
using System.Collections.Immutable;
using System.Linq;
-using System.Text;
namespace Funzo.SourceGenerators.Generators.Unions;
@@ -24,47 +25,36 @@ internal class UnionGenerator : GeneratorBase
var className = $"{classSymbol.Name}";
var typeArguments = type.AttributeTypeArguments;
- StringBuilder source = new($@"//
+ var sorse = WithSorse.CreateNamespaceScope(classSymbol.ContainingNamespace.ToDisplayString(), []);
-namespace {classSymbol.ContainingNamespace.ToDisplayString()}
-{{");
+ sorse.AddClassWithInnerClasses(type, AddUnionClass(type));
- // Add all needed upper classes
- foreach (var containingType in type.ContainerClasses)
- {
- var isStatic = type.Symbol.ContainingType!.IsStatic ? "static " : "";
-
- source.AppendLine($"{isStatic}partial class {containingType.Name} {{");
- }
-
- source.AppendLine($@" partial class {className} : global::{FunzoAttributeSources.AttributeNamespace}.Union{typeArguments.OpenGenericPart()}
- {{");
-
- foreach (var typeArgument in typeArguments)
- {
- source.Append($@"
- public {classSymbol.Name}({typeArgument.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)} _) : base(_) {{}}
- public static implicit operator {className}({typeArgument.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)} _) => new {className}(_);
-");
- }
+ var src = sorse.GetSource();
- foreach (var prop in commonProperties)
- {
- source.Append($@"
- public {prop.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)} {prop.Name} => Match({string.Join(",", Enumerable.Range(0, typeArguments.Length).Select(_ => $"x => x.{prop.Name}"))});
-");
- }
-
- // Close all the braces opened for parent classes
- source.AppendLine(new string('}', type.ContainerClasses.Count));
-
- source.Append(@" }
-}");
-
- var src = source.ToString();
return src;
}
+ private Action AddUnionClass(MarkedType type) =>
+ builder =>
+ {
+ var typeArguments = type.AttributeTypeArguments;
+ builder.Partial()
+ .Inherits($"global::{FunzoAttributeSources.AttributeNamespace}.Union{typeArguments.OpenGenericPart()}");
+
+ foreach (var typeArgument in typeArguments)
+ {
+ builder.WithConstructor(c => c.WithBaseCall(["_"]).WithArguments([new(new(typeArgument), "_")]));
+ builder.WithImplicitConversionOperatorFrom(new(typeArgument), " => new(x);");
+ }
+
+ var commonProperties = GetCommonProperties(type.AttributeTypeArguments);
+
+ foreach (var prop in commonProperties)
+ {
+ builder.WithProperty(new(prop.Type), prop.Name, p => p.WithComputedValue($" => Match({string.Join(",", Enumerable.Range(0, typeArguments.Length).Select(_ => $"x => x.{prop.Name}"))});"));
+ }
+ };
+
private bool HasErrors(SourceProductionContext context, MarkedType type)
{
var symbol = type.Symbol;
diff --git a/Funzo.SourceGenerators/Helpers/ContainerClass.cs b/Funzo.SourceGenerators/Helpers/ContainerClass.cs
index c02a2ef..e12380c 100644
--- a/Funzo.SourceGenerators/Helpers/ContainerClass.cs
+++ b/Funzo.SourceGenerators/Helpers/ContainerClass.cs
@@ -1,6 +1,7 @@
namespace Funzo.SourceGenerators.Helpers;
-public sealed class ContainerClass(string name)
+public sealed class ContainerClass(string name, bool isStatic)
{
public string Name { get; } = name;
+ public bool IsStatic { get; } = isStatic;
}
diff --git a/Funzo.SourceGenerators/Helpers/MarkedType.cs b/Funzo.SourceGenerators/Helpers/MarkedType.cs
index 5821c6d..4ea501b 100644
--- a/Funzo.SourceGenerators/Helpers/MarkedType.cs
+++ b/Funzo.SourceGenerators/Helpers/MarkedType.cs
@@ -26,7 +26,7 @@ private static Stack GenerateContainerClassesHierarchy(INamedTyp
while (container is not null)
{
- containers.Push(new(container.Name));
+ containers.Push(new(container.Name, container.IsStatic));
container = container.ContainingType;
}
diff --git a/Funzo.SourceGenerators/Helpers/SorseExtensions.cs b/Funzo.SourceGenerators/Helpers/SorseExtensions.cs
new file mode 100644
index 0000000..d08db6e
--- /dev/null
+++ b/Funzo.SourceGenerators/Helpers/SorseExtensions.cs
@@ -0,0 +1,66 @@
+using Sorse;
+using Sorse.BuilderInterfaces;
+using System;
+using System.Linq;
+
+namespace Funzo.SourceGenerators.Helpers;
+
+internal static class SorseExtensions
+{
+ internal static void AddClassWithInnerClasses(this INamespaceScope sorse, MarkedType type, Action builderAction)
+ {
+ var classSymbol = type.Symbol;
+ var className = $"{classSymbol.Name}";
+ var typeArguments = type.AttributeTypeArguments;
+
+ // TODO: Needs some rework. Feels off
+ if (!type.ContainerClasses.Any())
+ {
+ sorse.AddClass(className, builderAction);
+ }
+ else
+ {
+ var builder = GetClassBuilderFromContainingClasses(type, sorse);
+
+ // Add the main partial class
+ builder.WithInnerClass(className, builderAction);
+ }
+ }
+
+ private static IClassBuilder GetClassBuilderFromContainingClasses(MarkedType type, INamespaceScope sorse)
+ {
+ // Create the first class in the namespace
+ var container = type.ContainerClasses.Pop();
+
+ IClassBuilder builder = null!;
+
+ sorse.AddClass(container.Name, b =>
+ {
+ builder = b;
+ AddContainer(b, container);
+ });
+
+ // Nest the rest
+ foreach (var c in type.ContainerClasses)
+ {
+ builder.WithInnerClass(c.Name, b =>
+ {
+ builder = b;
+ AddContainer(b, c);
+ });
+
+ }
+
+ return builder;
+
+ static void AddContainer(IClassBuilder builder, ContainerClass c)
+ {
+ builder.Partial();
+
+ if (c.IsStatic)
+ {
+ builder.Static();
+ }
+ }
+ }
+}
diff --git a/Funzo.Test/UnionTests.cs b/Funzo.Test/UnionTests.cs
index 28af8b8..5a0410d 100644
--- a/Funzo.Test/UnionTests.cs
+++ b/Funzo.Test/UnionTests.cs
@@ -1,5 +1,4 @@
using System;
-using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;
namespace Funzo.Test;