generate glenum, link glenum, add source gen for text regex

This commit is contained in:
Youmu Liu
2026-08-31 18:12:44 +08:00
parent 667b8d8e43
commit e52d0ac6f3
54 changed files with 4555 additions and 1596 deletions
@@ -42,59 +42,76 @@ namespace StgSharp.GenerateGL.Generation
StringComparer.Ordinal);
public static GeneratedFileSet Generate(
GlRegistryProjection projection
GlRegistryProjection projection,
GlGenerationTarget target = GlGenerationTarget.All
)
{
ArgumentNullException.ThrowIfNull(projection);
if (target == GlGenerationTarget.None || (target & ~GlGenerationTarget.All) != 0)
{
throw new ArgumentOutOfRangeException(nameof(target));
}
IReadOnlyList<GlCommandGroup> commandGroups = ReadCoreCommandGroups(projection);
IReadOnlyList<GlCommandDefinition> commands = Array.AsReadOnly(
commandGroups.SelectMany(value => value.Commands).ToArray());
GlEquivalentTypeMapper typeMapper = new GlEquivalentTypeMapper(projection.Source);
GlFunctionFamilyAnalysis familyAnalysis = GlFunctionFamilyAnalyzer.Analyze(projection);
ManagedApiPlanner apiPlanner = new ManagedApiPlanner(typeMapper, familyAnalysis);
IReadOnlyList<ManagedMethodDefinition> managedMethods = apiPlanner.Plan(commands);
Dictionary<string, IReadOnlyList<ManagedMethodDefinition>> methodsByCommand =
managedMethods.GroupBy(value => value.NativeCommand.Name, StringComparer.Ordinal)
.ToDictionary(
value => value.Key,
value => (IReadOnlyList<ManagedMethodDefinition>)Array.AsReadOnly(
value.ToArray()),
StringComparer.Ordinal);
List<ManagedCommandGroup> managedGroups = commandGroups.Select(
group => new ManagedCommandGroup(
group,
Array.AsReadOnly(
group.Commands.SelectMany(
command => methodsByCommand.TryGetValue(
command.Name,
out IReadOnlyList<ManagedMethodDefinition>? methods)
? methods
: Array.Empty<ManagedMethodDefinition>())
.ToArray()))).ToList();
ManagedApiPlanner.Validate(
managedGroups.SelectMany(value => value.Methods));
List<GeneratedFile> files = new List<GeneratedFile>
IReadOnlyList<ManagedEnumDefinition> enums = GlEnumProjector.Project(projection);
GlEnumTypeMap enumTypeMap = new GlEnumTypeMap(enums);
List<GeneratedFile> files = new List<GeneratedFile>();
if ((target & GlGenerationTarget.Enum) != 0)
{
new GeneratedFile("glconst.cs", GenerateConstants(projection.Enums)),
new GeneratedFile(
files.Add(new GeneratedFile("glconst.cs", GenerateConstants(projection.Enums)));
files.Add(new GeneratedFile("GlEnums.g.cs", GenerateEnums(enums)));
}
if ((target & GlGenerationTarget.Api) != 0)
{
IReadOnlyList<GlCommandGroup> commandGroups = ReadCoreCommandGroups(projection);
IReadOnlyList<GlCommandDefinition> commands = Array.AsReadOnly(
commandGroups.SelectMany(value => value.Commands).ToArray());
GlEquivalentTypeMapper typeMapper = new GlEquivalentTypeMapper(projection.Source);
GlFunctionFamilyAnalysis familyAnalysis = GlFunctionFamilyAnalyzer.Analyze(projection);
ManagedApiPlanner apiPlanner = new ManagedApiPlanner(
typeMapper,
familyAnalysis,
enumTypeMap);
IReadOnlyList<ManagedMethodDefinition> managedMethods = apiPlanner.Plan(commands);
Dictionary<string, IReadOnlyList<ManagedMethodDefinition>> methodsByCommand =
managedMethods.GroupBy(value => value.NativeCommand.Name, StringComparer.Ordinal)
.ToDictionary(
value => value.Key,
value => (IReadOnlyList<ManagedMethodDefinition>)Array.AsReadOnly(
value.ToArray()),
StringComparer.Ordinal);
List<ManagedCommandGroup> managedGroups = commandGroups.Select(
group => new ManagedCommandGroup(
group,
Array.AsReadOnly(
group.Commands.SelectMany(
command => methodsByCommand.TryGetValue(
command.Name,
out IReadOnlyList<ManagedMethodDefinition>? methods)
? methods
: Array.Empty<ManagedMethodDefinition>())
.ToArray()))).ToList();
ManagedApiPlanner.Validate(
managedGroups.SelectMany(value => value.Methods));
files.Add(new GeneratedFile(
"OpenglContext.g.cs",
GenerateContext(commands, typeMapper)),
new GeneratedFile(
GenerateContext(commands, typeMapper)));
files.Add(new GeneratedFile(
"glContextShadow.g.cs",
GenerateContextShadow(commands)),
};
for (int index = 0; index < managedGroups.Count; index++)
{
ManagedCommandGroup managedGroup = managedGroups[index];
GlCommandGroup group = managedGroup.Source;
files.Add(
new GeneratedFile(
group.FileName,
GenerateFunctions(
managedGroup.Methods,
group.Description,
index == 0)));
GenerateContextShadow(commands)));
for (int index = 0; index < managedGroups.Count; index++)
{
ManagedCommandGroup managedGroup = managedGroups[index];
GlCommandGroup group = managedGroup.Source;
files.Add(
new GeneratedFile(
group.FileName,
GenerateFunctions(
managedGroup.Methods,
group.FileName,
group.Description,
index == 0)));
}
}
return new GeneratedFileSet(files);
@@ -184,7 +201,7 @@ namespace StgSharp.GenerateGL.Generation
)
{
StringBuilder builder = new StringBuilder(512 * 1024);
AppendGeneratedHeader(builder, "Desktop OpenGL constants");
AppendGeneratedHeader(builder, "glconst.cs", "Desktop OpenGL constants");
builder.Append("namespace StgSharp.Graphics.OpenGL\n");
builder.Append("{\n");
builder.Append(" public static class glConst\n");
@@ -227,6 +244,60 @@ namespace StgSharp.GenerateGL.Generation
return builder.ToString();
}
private static string GenerateEnums(
IReadOnlyList<ManagedEnumDefinition> enums
)
{
StringBuilder builder = new StringBuilder(512 * 1024);
AppendGeneratedHeader(
builder,
"GlEnums.g.cs",
"Strongly typed desktop OpenGL enum groups");
builder.Append("namespace StgSharp.Graphics.OpenGL\n");
builder.Append("{\n");
foreach (ManagedEnumDefinition value in enums)
{
builder.Append(" /// <summary>Native OpenGL group");
builder.Append(value.NativeGroups.Count == 1 ? " " : "s ");
builder.Append(string.Join(", ", value.NativeGroups));
builder.Append(".</summary>\n");
if (value.IsFlags)
{
builder.Append(" [System.Flags]\n");
}
builder.Append(" public enum ");
builder.Append(value.Name);
builder.Append(" : uint\n");
builder.Append(" {\n");
foreach (ManagedEnumMemberDefinition member in value.Members)
{
builder.Append(" ");
builder.Append(member.Name);
builder.Append(" = ");
if (member.NativeValue.Name == "GL_NONE" &&
member.NativeValue.Comment ==
"Synthetic zero value for a generated flags enum.")
{
builder.Append("0u");
}
else
{
builder.Append("unchecked((uint)glConst.");
builder.Append(ReadConstantName(member.NativeValue.Name));
builder.Append(')');
}
builder.Append(",\n");
}
builder.Append(" }\n\n");
}
builder.Append("}\n");
return builder.ToString();
}
private static ConstantExpression ReadConstantExpression(
GlEnumDefinition value
)
@@ -329,7 +400,10 @@ namespace StgSharp.GenerateGL.Generation
)
{
StringBuilder builder = new StringBuilder(128 * 1024);
AppendGeneratedHeader(builder, "Desktop OpenGL core function pointer table");
AppendGeneratedHeader(
builder,
"OpenglContext.g.cs",
"Desktop OpenGL core function pointer table");
builder.Append("namespace StgSharp.Graphics.OpenGL\n");
builder.Append("{\n");
builder.Append(" [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]\n");
@@ -360,7 +434,10 @@ namespace StgSharp.GenerateGL.Generation
)
{
StringBuilder builder = new StringBuilder(64 * 1024);
AppendGeneratedHeader(builder, "Native-address shadow of the OpenGL function pointer table");
AppendGeneratedHeader(
builder,
"glContextShadow.g.cs",
"Native-address shadow of the OpenGL function pointer table");
builder.Append("namespace StgSharp.Graphics.OpenGL\n");
builder.Append("{\n");
builder.Append(" [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]\n");
@@ -389,13 +466,14 @@ namespace StgSharp.GenerateGL.Generation
private static string GenerateFunctions(
IReadOnlyList<ManagedMethodDefinition> methods,
string outputFileName,
string description,
bool includeContextState
)
{
StringBuilder builder = new StringBuilder(512 * 1024);
AppendGeneratedHeader(builder, description);
builder.Append("using StgSharp.Mathematics.Graphics;\n\n");
AppendGeneratedHeader(builder, outputFileName, description);
builder.Append("using StgSharp.Mathematics.Numeric.Graphics;\n\n");
builder.Append("using System;\n");
builder.Append("using System.Runtime.CompilerServices;\n\n");
builder.Append("namespace StgSharp.Graphics.OpenGL\n");
@@ -572,6 +650,12 @@ namespace StgSharp.GenerateGL.Generation
{
builder.Append("return GlHandle.Create(");
}
else if (method.IsEnumReturn)
{
builder.Append("return (");
builder.Append(method.ReturnType);
builder.Append(')');
}
else if (method.ReturnType != "void")
{
builder.Append("return ");
@@ -719,7 +803,14 @@ namespace StgSharp.GenerateGL.Generation
ManagedParameterDefinition parameter = method.Parameters[
parameterArgument.ParameterIndex];
string parameterName = EscapeIdentifier(parameter.Name);
if (!parameter.IsHandle)
if (parameter.IsEnum)
{
builder.Append("(uint");
builder.Append('*', parameter.Type.Count(value => value == '*'));
builder.Append(')');
builder.Append(parameterName);
}
else if (!parameter.IsHandle)
{
builder.Append(parameterName);
}
@@ -769,9 +860,18 @@ namespace StgSharp.GenerateGL.Generation
private static void AppendGeneratedHeader(
StringBuilder builder,
string outputFileName,
string description
)
{
builder.Append("// -----------------------------------------------------------------------------\n");
builder.Append("// file=\"");
builder.Append(ReadGeneratedFileName(outputFileName));
builder.Append("\"\n");
builder.Append("// Project: StgSharp\n");
builder.Append("// Copyright (c) Nitload.\n");
builder.Append("// SPDX-License-Identifier: MIT\n");
builder.Append("// -----------------------------------------------------------------------------\n\n");
builder.Append("// <auto-generated>\n");
builder.Append("// Generated by StgSharp.GenerateGL.\n");
builder.Append("// ");
@@ -780,6 +880,22 @@ namespace StgSharp.GenerateGL.Generation
builder.Append("// </auto-generated>\n\n");
}
private static string ReadGeneratedFileName(
string outputFileName
)
{
const string generatedExtension = ".g.cs";
const string sourceExtension = ".cs";
if (outputFileName.EndsWith(generatedExtension, StringComparison.Ordinal))
{
return outputFileName[..^generatedExtension.Length];
}
return outputFileName.EndsWith(sourceExtension, StringComparison.Ordinal)
? outputFileName[..^sourceExtension.Length]
: outputFileName;
}
private sealed record ConstantExpression(
string Type,
string Literal