Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion Generator.Tests/PietMethodGeneratorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
54 changes: 16 additions & 38 deletions Generator/MethodGenerator.Runtime.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Microsoft.CodeAnalysis.CSharp;
using System.Text;

namespace Esolang.Piet.Generator;
Expand All @@ -7,7 +8,7 @@ partial class MethodGenerator
/// <summary>
/// The generated file name for the shared Piet interpreter runtime.
/// </summary>
public const string GeneratePietRuntimeFileName = "PietRuntime.g.cs";
public const string GeneratePietRuntimeFileName = GeneratedMethodsFileName;

/// <summary>
/// The features that may be needed by the generated methods.
Expand Down Expand Up @@ -40,12 +41,10 @@ enum GeneratorFeatures
/// <summary>
/// Tries to generate the source code for the shared Piet interpreter runtime if needed.
/// </summary>
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;
Expand All @@ -60,20 +59,13 @@ Func<string, string, string, string> callLogExecuting

"""
: static (_, _, _) => string.Empty;
var builder = new StringBuilder();
builder.AppendLine("""
// <auto-generated/>
#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[]
{
Expand Down Expand Up @@ -912,10 +904,10 @@ internal static async IAsyncEnumerable<byte> 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<global::Microsoft.Extensions.Logging.ILogger, int, int, int, global::System.Exception?> ExecutingCommand =
global::Microsoft.Extensions.Logging.LoggerMessage.Define<int, int, int>(global::Microsoft.Extensions.Logging.LogLevel.Trace, 0, "Executing Piet command: op={Op}, value={Value}, index={Index}");
Expand All @@ -934,46 +926,35 @@ public static void LogExecuting(global::Microsoft.Extensions.Logging.ILogger? lo
}
""");

filename = GeneratePietRuntimeFileName;
source = builder.ToString();
return true;
}

/// <summary>
/// The generated file name for the shared Piet++ interpreter runtime.
/// </summary>
public const string GeneratePietPlusPlusRuntimeFileName = "PietPlusPlusRuntime.g.cs";
public const string GeneratePietPlusPlusRuntimeFileName = GeneratedMethodsFileName;

/// <summary>
/// Tries to generate the source code for the shared Piet++ interpreter runtime if needed.
/// </summary>
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("""
// <auto-generated/>
#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<PietPlusPlusValue>? _stack;
Expand All @@ -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;
Expand Down Expand Up @@ -1593,8 +1574,5 @@ public static async IAsyncEnumerable<byte> ExecuteAsyncEnumerable(
}
""");

filename = GeneratePietPlusPlusRuntimeFileName;
source = builder.ToString();
return true;
}
}
21 changes: 17 additions & 4 deletions Generator/MethodGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

""";

Expand Down Expand Up @@ -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);
});
}

Expand Down Expand Up @@ -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<AdditionalImageFile> additionalImageFiles)
{
const string dataUrlStarts = "data:";
Expand Down
Loading