From c0ced19bc98969429c3a48948baaa79c6e0f6db9 Mon Sep 17 00:00:00 2001 From: Thad House Date: Thu, 15 Feb 2024 17:04:55 -0800 Subject: [PATCH] Lots more source generation --- .../MonologueSourceGenerator/LogGenerator.cs | 81 +++++++++++++++---- src/thirdparty/Monologue/Monologuer.cs | 20 +++++ test/monologue.test/TestTree.cs | 23 +++--- 3 files changed, 97 insertions(+), 27 deletions(-) diff --git a/sourcegeneration/MonologueSourceGenerator/LogGenerator.cs b/sourcegeneration/MonologueSourceGenerator/LogGenerator.cs index 800adf0c..b1259536 100644 --- a/sourcegeneration/MonologueSourceGenerator/LogGenerator.cs +++ b/sourcegeneration/MonologueSourceGenerator/LogGenerator.cs @@ -6,7 +6,9 @@ namespace Monologue.SourceGenerator; -internal record ClassData(ImmutableArray LoggedItems, string Name, string ClassDeclaration, string? Namespace); +internal record LogData(string? PreComputed, string? GetOperation, string? Path, string? Type); + +internal record ClassData(ImmutableArray LoggedItems, string Name, string ClassDeclaration, string? Namespace); [Generator] public class LogGenerator : IIncrementalGenerator @@ -27,7 +29,7 @@ public class LogGenerator : IIncrementalGenerator var classMembers = classSymbol.GetMembers(); - var loggableMembers = ImmutableArray.CreateBuilder(classMembers.Length); + var loggableMembers = ImmutableArray.CreateBuilder(classMembers.Length); foreach (var member in classMembers) { @@ -82,17 +84,7 @@ public class LogGenerator : IIncrementalGenerator throw new InvalidOperationException("Field is not loggable"); } - string fullOperation; - - if (logType.AllInterfaces.Where(x => x.ToDisplayString() == "Monologue.ILogged").Any()) - { - fullOperation = $"{getOperation}.UpdateMonologue($\"{{path}}/{defaultPathName}\", logger);"; - } - else - { - // TODO the rest of the types - fullOperation = ""; - } + var fullOperation = ComputeOperation(logType, getOperation, defaultPathName); token.ThrowIfCancellationRequested(); loggableMembers.Add(fullOperation); break; @@ -103,6 +95,37 @@ public class LogGenerator : IIncrementalGenerator return new ClassData(loggableMembers.ToImmutable(), classSymbol.Name, typeBuilder.ToString(), ns); } + private static LogData ComputeOperation(ITypeSymbol logType, string getOp, string path) + { + if (logType.GetAttributes().Where(x => x.AttributeClass?.ToDisplayString() == "Monologue.GenerateLogAttribute").Any()) + { + return new($"{getOp}.UpdateMonologue($\"{{path}}/{path}\", logger);", null, null, null); + } + if (logType.AllInterfaces.Where(x => x.ToDisplayString() == "Monologue.ILogged").Any()) + { + return new($"{getOp}.UpdateMonologue($\"{{path}}/{path}\", logger);", null, null, null); + //return $"{getOp}.UpdateMonologue($\"{{path}}/{path}\", logger);"; + } + var fullName = logType.ToDisplayString(); + var structName = $"WPIUtil.Serialization.Struct.IStructSerializable<{fullName}>"; + var protobufName = $"WPIUtil.Serialization.Protobuf.IProtobufSerializable<{fullName}>"; + foreach (var inf in logType.AllInterfaces) + { + var interfaceName = inf.ToDisplayString(); + // For now prefer struct + if (interfaceName == structName) + { + return new($"logger.LogStruct($\"{{path}}/{path}\", LogType.Nt, {getOp});", null, null, null); + } + else if (interfaceName == protobufName) + { + return new($"logger.LogProto($\"{{path}}/{path}\", LogType.Nt, {getOp});", null, null, null); + } + } + + return new(null, getOp, path, fullName); + } + public void Initialize(IncrementalGeneratorInitializationContext context) { var attributedTypes = context.SyntaxProvider @@ -116,6 +139,33 @@ public void Initialize(IncrementalGeneratorInitializationContext context) static (spc, source) => Execute(source, spc)); } + static void ConstructCall(LogData data, StringBuilder builder) + { + if (data.PreComputed is not null) { + + builder.AppendLine($" {data.PreComputed}"); + return; + } + + var ret = data.Type switch { + "float" => ("LogFloat", ""), + "double" => ("LogDouble", ""), + "byte" => ("LogInteger", ""), + "sbyte" => ("LogInteger", ""), + "short" => ("LogInteger", ""), + "ushort" => ("LogInteger", ""), + "int" => ("LogInteger", ""), + "uint" => ("LogInteger", ""), + "long" => ("LogInteger", ""), + "ulong" => ("LogInteger", "(long)"), + "bool" => ("LogBoolean", ""), + "char" => ("LogChar", ""), + _ => (data.Type, "") + }; + + builder.AppendLine($" logger.{ret.Item1}($\"{{path}}/{data.Path}\", LogType.Nt, {ret.Item2}{data.GetOperation});"); + } + static void Execute(ClassData? classData, SourceProductionContext context) { if (classData is { } value) @@ -126,14 +176,13 @@ static void Execute(ClassData? classData, SourceProductionContext context) builder.AppendLine($"namespace {value.Namespace};"); builder.AppendLine(); - builder.Append(value.ClassDeclaration); - builder.AppendLine(" : ILogged"); + builder.AppendLine(value.ClassDeclaration); builder.AppendLine("{"); builder.AppendLine(" public void UpdateMonologue(string path, Monologue.Monologuer logger)"); builder.AppendLine(" {"); foreach (var call in value.LoggedItems) { - builder.AppendLine($" {call}"); + ConstructCall(call, builder); } builder.AppendLine(" }"); builder.AppendLine("}"); diff --git a/src/thirdparty/Monologue/Monologuer.cs b/src/thirdparty/Monologue/Monologuer.cs index 6c052fbb..2ef65620 100644 --- a/src/thirdparty/Monologue/Monologuer.cs +++ b/src/thirdparty/Monologue/Monologuer.cs @@ -29,6 +29,7 @@ public static void UpdateAll(ILogged logged) private readonly DataLog log = null!; + private readonly Dictionary integerLogs = []; private readonly Dictionary booleanLogs = []; private readonly Dictionary structLogs = []; @@ -51,6 +52,25 @@ public void LogBoolean(string path, LogType logType, bool value) } } + public void LogInteger(string path, LogType logType, long value) + { + if (logType == LogType.None) + { + return; + } + ref var logs = ref CollectionsMarshal.GetValueRefOrAddDefault(integerLogs, path, out _); + if (logType.HasFlag(LogType.Nt)) + { + logs.topic ??= NetworkTableInstance.Default.GetIntegerTopic(path).Publish(PubSubOptions.None); + logs.topic.Set(value); + } + if (logType.HasFlag(LogType.File)) + { + logs.logEntry ??= new IntegerLogEntry(log, path); + logs.logEntry.Append(value); + } + } + public void LogStruct(string path, LogType logType, in T value) where T : IStructSerializable { if (logType == LogType.None) diff --git a/test/monologue.test/TestTree.cs b/test/monologue.test/TestTree.cs index ce88b39d..cd89af92 100644 --- a/test/monologue.test/TestTree.cs +++ b/test/monologue.test/TestTree.cs @@ -7,6 +7,8 @@ public partial class GenerateGenericClass { [Log] public int Variable { get; } + [Log] + public Int32 Variable2 { get; } } [GenerateLog] @@ -103,26 +105,25 @@ public partial class TestRootClass public TestStruct TS { get; } = new(); } -public class TestClass : ILogged +[GenerateLog] +public partial class TestClass { [Log] public TestStruct TS { get; } = new(); - - public void UpdateMonologue(string path, Monologuer logger) - { - TS.UpdateMonologue($"{path}/TS", logger); - } } -public struct TestStruct : ILogged +[GenerateLog] +public partial struct TestStruct { [Log] public Rotation2d Rotation { get; set; } = new(); public TestStruct() { } +} - public readonly void UpdateMonologue(string path, Monologuer logger) - { - logger.LogStruct($"{path}/Rotation", LogType.Nt, Rotation); - } +[GenerateLog] +public partial class TestDemo +{ + [Log] + public Rotation2d Rotation { get; set; } = new(); }