diff --git a/src/gaemstone.SourceGen/ModuleGenerator.cs b/src/gaemstone.SourceGen/ModuleGenerator.cs index 825500f..e4f3b6a 100644 --- a/src/gaemstone.SourceGen/ModuleGenerator.cs +++ b/src/gaemstone.SourceGen/ModuleGenerator.cs @@ -209,8 +209,10 @@ public class ModuleGenerator sb.AppendLine("\t\t\t\tnew("); foreach (var p in m.Parameters) if (p.HasTerm) { - // TODO: Throw error if multiple Or terms appear next to each other. - foreach (var term in p.TermTypes) { + for (var i = 0; i < p.TermTypes.Count; i++) { + var term = p.TermTypes[i]; + var isLastTerm = (i == p.TermTypes.Count - 1); + sb.Append($"\t\t\t\t\tnew Term("); switch (term) { case ITypeSymbol type: @@ -225,14 +227,17 @@ public class ModuleGenerator $"Unexpected term type {term.GetType()}"); } sb.Append(')'); + if (p.Source != null) { sb.Append("{ Source = "); AppendTypeEntity(sb, module, p.Source); sb.Append(" }"); } + + // The last term in a group of OR terms must not have the TermOperKind.Or set. + if (p.IsOr && !isLastTerm) sb.Append(".Or"); + sb.Append(p.Kind switch { - ParameterKind.Or => ".Or", - ParameterKind.HasOr => ".Or.None", ParameterKind.Has => ".None", ParameterKind.Not => ".None.Not", ParameterKind.Ref => ".InOut", @@ -240,7 +245,9 @@ public class ModuleGenerator _ when !p.IsValueType => ".InOut", // Reference types always imply writability. _ => ".In", }); + if (p.IsNullable) sb.Append(".Optional"); + sb.AppendLine(","); } } @@ -317,6 +324,9 @@ public class ModuleGenerator if (method.IsGeneric) sb.Append(""); sb.Append($"("); foreach (var param in method.Parameters) { + // TODO: Support [Or<...>] + if (param.IsOr && (param.Kind != ParameterKind.Has)) + throw new NotSupportedException($"Or<...> parameter not yet supported"); switch (param.Kind) { case ParameterKind.Unique: sb.Append(param.UniqueReplacement); @@ -338,13 +348,8 @@ public class ModuleGenerator case ParameterKind.Has: case ParameterKind.Not: - case ParameterKind.HasOr: sb.Append("default"); break; - - case ParameterKind.Or: - throw new NotSupportedException( - $"ParameterKind {param.Kind} not supported"); } sb.Append(", "); } @@ -363,6 +368,7 @@ public class ModuleGenerator StringBuilder sb, ModuleEntityInfo module, ITypeSymbol type) { + // TODO: Cache entity lookup. var found = module.Children.Where(c => !c.IsErrored) .Any(c => SymbolEqualityComparer.Default.Equals(c.Symbol, type)); sb.Append(found ? $"_{type.Name}_Entity" diff --git a/src/gaemstone.SourceGen/Structure/ParameterInfo.cs b/src/gaemstone.SourceGen/Structure/ParameterInfo.cs index aa8177c..6615c6a 100644 --- a/src/gaemstone.SourceGen/Structure/ParameterInfo.cs +++ b/src/gaemstone.SourceGen/Structure/ParameterInfo.cs @@ -35,9 +35,10 @@ public class ParameterInfo : BaseInfo public IReadOnlyList TermTypes { get; } // Either ITypeSymbol or Pair for relationships. public ITypeSymbol? FieldType { get; } public ParameterKind Kind { get; } + public bool IsOr { get; } public bool HasTerm => (Kind != ParameterKind.Unique); - public bool HasField => HasTerm && !(Kind is ParameterKind.Has or ParameterKind.Not or ParameterKind.HasOr); + public bool HasField => HasTerm && !(Kind is ParameterKind.Has or ParameterKind.Not); public ParameterInfo(ISymbol symbol) : base(symbol) @@ -49,15 +50,16 @@ public class ParameterInfo : BaseInfo var typeFullName = Symbol.Type.GetFullName(FullNameStyle.Metadata); if (UniqueParameters.TryGetValue(typeFullName, out var replacement)) { + IsOr = false; Kind = ParameterKind.Unique; TermTypes = Array.Empty(); UniqueReplacement = replacement; } else { + IsOr = typeFullName.StartsWith("gaemstone.ECS.Or"); var isHas = typeFullName.StartsWith("gaemstone.ECS.Has"); var isNot = typeFullName.StartsWith("gaemstone.ECS.Not"); - var isOr = typeFullName.StartsWith("gaemstone.ECS.Or"); if (IsGeneric) { @@ -71,7 +73,7 @@ public class ParameterInfo : BaseInfo { TermTypes = argType.TypeArguments.ToImmutableList(); FieldType = null; - isOr = true; + IsOr = true; } else if ((isHas || isNot) && (args is [ INamedTypeSymbol relation, INamedTypeSymbol target ])) { @@ -90,11 +92,9 @@ public class ParameterInfo : BaseInfo FieldType = Symbol.Type; } - Kind = (isHas && isOr) ? ParameterKind.HasOr - : isHas ? ParameterKind.Has - : isOr ? ParameterKind.Or - : isNot ? ParameterKind.Not - : IsNullable ? ParameterKind.Nullable + Kind = isHas ? ParameterKind.Has + : isNot ? ParameterKind.Not + : IsNullable ? ParameterKind.Nullable : Symbol.RefKind switch { RefKind.In => ParameterKind.In, RefKind.Out => ParameterKind.Out, @@ -141,8 +141,7 @@ public class ParameterInfo : BaseInfo } else { - var isSpecial = Kind is ParameterKind.Has or ParameterKind.HasOr - or ParameterKind.Or or ParameterKind.Not; + var isSpecial = IsOr || (Kind is ParameterKind.Has or ParameterKind.Not); if (isSpecial && IsByRef) yield return Diagnostic.Create( Descriptors.SpecialMustNotBeByRef, Location); if (isSpecial && IsNullable) yield return Diagnostic.Create( @@ -202,8 +201,6 @@ public enum ParameterKind Ref, // Pass by reference (read/write) Has, // Required present (no read/write) Not, // Required missing (no read/write) - Or, // Only one of multiple terms is required - HasOr, // Both Has and Or at the same time } // public enum TermKind