From 89b792340e5d8aaf9c30dac56e2f4d75daa72527 Mon Sep 17 00:00:00 2001 From: juner Date: Sat, 6 Jun 2026 01:13:47 +0900 Subject: [PATCH] fix: update method generation logic to append runtime source correctly --- Generator.Tests/PietMethodGeneratorTests.cs | 7 ++- Generator/MethodGenerator.Runtime.cs | 54 ++++++--------------- Generator/MethodGenerator.cs | 21 ++++++-- 3 files changed, 39 insertions(+), 43 deletions(-) diff --git a/Generator.Tests/PietMethodGeneratorTests.cs b/Generator.Tests/PietMethodGeneratorTests.cs index 68e8f6e..b079fb0 100644 --- a/Generator.Tests/PietMethodGeneratorTests.cs +++ b/Generator.Tests/PietMethodGeneratorTests.cs @@ -1617,7 +1617,12 @@ public partial class Sample .FirstOrDefault(static t => t.Contains("partial class Sample")) ?? string.Empty; Assert.Contains("public static partial", generatedMethod, "Expected static modifier was not found."); - Assert.DoesNotContain("namespace ", generatedMethod, "Global namespace method should not emit a namespace declaration."); + // The runtime is appended after the method code in the combined file; extract only the method section. + const string runtimeSeparator = "\nnamespace Esolang.Piet.__Generated"; + var methodSection = generatedMethod.Contains(runtimeSeparator) + ? generatedMethod[..generatedMethod.IndexOf(runtimeSeparator, StringComparison.Ordinal)] + : generatedMethod; + Assert.DoesNotContain("namespace ", methodSection, "Global namespace method should not emit a namespace declaration."); } catch (Exception e) when (e is AssertFailedException or TargetInvocationException) { diff --git a/Generator/MethodGenerator.Runtime.cs b/Generator/MethodGenerator.Runtime.cs index 0ecfabd..ac6eb6a 100644 --- a/Generator/MethodGenerator.Runtime.cs +++ b/Generator/MethodGenerator.Runtime.cs @@ -1,3 +1,4 @@ +using Microsoft.CodeAnalysis.CSharp; using System.Text; namespace Esolang.Piet.Generator; @@ -7,7 +8,7 @@ partial class MethodGenerator /// /// The generated file name for the shared Piet interpreter runtime. /// - public const string GeneratePietRuntimeFileName = "PietRuntime.g.cs"; + public const string GeneratePietRuntimeFileName = GeneratedMethodsFileName; /// /// The features that may be needed by the generated methods. @@ -40,12 +41,10 @@ enum GeneratorFeatures /// /// Tries to generate the source code for the shared Piet interpreter runtime if needed. /// - static bool TryMakePietRuntimeSource(GeneratorFeatures features, out string filename, out string source) + static void AppendPietRuntimeSource(GeneratorFeatures features, LanguageVersion languageVersion, StringBuilder builder) { - filename = default!; - source = default!; if (features == GeneratorFeatures.None) - return false; + return; var enableLogging = (features & GeneratorFeatures.UseLogging) != 0; // `logger? = null,` or string.Emtpy var withLoggingParameter = enableLogging ? "global::Microsoft.Extensions.Logging.ILogger? logger = null," : string.Empty; @@ -60,20 +59,13 @@ Func callLogExecuting """ : static (_, _, _) => string.Empty; - var builder = new StringBuilder(); - builder.AppendLine(""" - // - #nullable enable - #pragma warning disable CS1591 - using System; - using System.ComponentModel; - using System.Collections.Generic; - using System.Threading; + var fileOrInternal = IsLanguageVersionAtLeastCSharp11(languageVersion) ? "file" : "internal"; + builder.AppendLine($$""" namespace Esolang.Piet.__Generated { [EditorBrowsable(EditorBrowsableState.Never)] - internal static class PietRuntime + {{fileOrInternal}} static class PietRuntime { private static readonly int[] s_hue = new int[] { @@ -912,10 +904,10 @@ internal static async IAsyncEnumerable ExecuteAsyncEnumerable( """); if ((features & GeneratorFeatures.UseLogging) != 0) - builder.AppendLine(""" + builder.AppendLine($$""" [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] - internal static class LoggerUtilities + {{fileOrInternal}} static class LoggerUtilities { private static readonly global::System.Action ExecutingCommand = global::Microsoft.Extensions.Logging.LoggerMessage.Define(global::Microsoft.Extensions.Logging.LogLevel.Trace, 0, "Executing Piet command: op={Op}, value={Value}, index={Index}"); @@ -934,46 +926,35 @@ public static void LogExecuting(global::Microsoft.Extensions.Logging.ILogger? lo } """); - filename = GeneratePietRuntimeFileName; - source = builder.ToString(); - return true; } /// /// The generated file name for the shared Piet++ interpreter runtime. /// - public const string GeneratePietPlusPlusRuntimeFileName = "PietPlusPlusRuntime.g.cs"; + public const string GeneratePietPlusPlusRuntimeFileName = GeneratedMethodsFileName; /// /// Tries to generate the source code for the shared Piet++ interpreter runtime if needed. /// - static bool TryMakePietPlusPlusRuntimeSource(GeneratorFeatures features, out string filename, out string source) + static void AppendPietPlusPlusRuntimeSource(GeneratorFeatures features, LanguageVersion languageVersion, StringBuilder builder) { - filename = default!; - source = default!; var ppFeatures = features & (GeneratorFeatures.SyncPlusPlus | GeneratorFeatures.AsyncPlusPlus | GeneratorFeatures.EnumerablePlusPlus | GeneratorFeatures.AsyncEnumerablePlusPlus); if (ppFeatures == GeneratorFeatures.None) - return false; + return; var needsSync = (ppFeatures & (GeneratorFeatures.SyncPlusPlus | GeneratorFeatures.EnumerablePlusPlus)) != 0; var needsAsync = (ppFeatures & (GeneratorFeatures.AsyncPlusPlus | GeneratorFeatures.AsyncEnumerablePlusPlus)) != 0; var needsEnumerable = (ppFeatures & GeneratorFeatures.EnumerablePlusPlus) != 0; var needsAsyncEnumerable = (ppFeatures & GeneratorFeatures.AsyncEnumerablePlusPlus) != 0; - var builder = new StringBuilder(); - builder.AppendLine(""" - // - #nullable enable - #pragma warning disable CS1591 - using System; - using System.Collections.Generic; - using System.Threading; + var fileOrInternal = IsLanguageVersionAtLeastCSharp11(languageVersion) ? "file" : "internal"; + builder.AppendLine($$""" namespace Esolang.Piet.__Generated { [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] - internal readonly struct PietPlusPlusValue + {{fileOrInternal}} readonly struct PietPlusPlusValue { readonly int _intVal; readonly List? _stack; @@ -987,7 +968,7 @@ internal readonly struct PietPlusPlusValue } [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] - internal static class PietPlusPlusRuntime + {{fileOrInternal}} static class PietPlusPlusRuntime { private const byte Black = 0; private const byte White = 63; @@ -1593,8 +1574,5 @@ public static async IAsyncEnumerable ExecuteAsyncEnumerable( } """); - filename = GeneratePietPlusPlusRuntimeFileName; - source = builder.ToString(); - return true; } } diff --git a/Generator/MethodGenerator.cs b/Generator/MethodGenerator.cs index ac3e4f2..c091f0c 100644 --- a/Generator/MethodGenerator.cs +++ b/Generator/MethodGenerator.cs @@ -44,7 +44,12 @@ public partial class MethodGenerator : IIncrementalGenerator {{CommentAutoGenerated}} #nullable enable #pragma warning disable CS0219 + #pragma warning disable CS1591 #pragma warning disable CS1998 + using System; + using System.ComponentModel; + using System.Collections.Generic; + using System.Threading; """; @@ -195,12 +200,10 @@ parseOptions is CSharpParseOptions csharpParseOptions if (emittedCount > 0) { + AppendPietRuntimeSource(features, currentLanguageVersion, builder); + AppendPietPlusPlusRuntimeSource(features, currentLanguageVersion, builder); context.AddSource(GeneratedMethodsFileName, builder.ToString()); } - if (TryMakePietRuntimeSource(features, out var runtimeFileName, out var runtimeSource)) - context.AddSource(runtimeFileName, runtimeSource); - if (TryMakePietPlusPlusRuntimeSource(features, out var ppRuntimeFileName, out var ppRuntimeSource)) - context.AddSource(ppRuntimeFileName, ppRuntimeSource); }); } @@ -1194,6 +1197,16 @@ static bool IsLanguageVersionAtLeastCSharp8(LanguageVersion languageVersion) _ => languageVersion >= LanguageVersion.CSharp8, }; + static bool IsLanguageVersionAtLeastCSharp11(LanguageVersion languageVersion) + => languageVersion switch + { + LanguageVersion.Default => true, + LanguageVersion.Latest => true, + LanguageVersion.Preview => true, + LanguageVersion.LatestMajor => true, + _ => languageVersion >= LanguageVersion.CSharp11, + }; + static AdditionalImageFile? TryResolveImagePath(string imagePath, ImmutableArray additionalImageFiles) { const string dataUrlStarts = "data:";