mirror of
https://git.naxdy.org/Mirror/Ryujinx.git
synced 2026-03-24 09:57:42 +00:00
93 lines
3.9 KiB
C#
93 lines
3.9 KiB
C#
using Microsoft.CodeAnalysis;
|
|
using Microsoft.CodeAnalysis.CSharp;
|
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
|
|
namespace Ryujinx.HLE.Generators
|
|
{
|
|
[Generator]
|
|
public sealed class UserServiceGenerator : IIncrementalGenerator
|
|
{
|
|
private sealed class ServiceData : IEquatable<ServiceData>
|
|
{
|
|
public required string FullName { get; init; }
|
|
public required IReadOnlyList<(string ServiceName, string ParameterValue)> Instances { get; init; }
|
|
|
|
public override bool Equals(object obj)
|
|
=> obj is ServiceData data && Equals(data);
|
|
|
|
public bool Equals(ServiceData other)
|
|
{
|
|
return this.FullName == other.FullName && this.Instances.SequenceEqual(other.Instances);
|
|
}
|
|
|
|
public override int GetHashCode() => FullName.GetHashCode();
|
|
}
|
|
|
|
public void Initialize(IncrementalGeneratorInitializationContext context)
|
|
{
|
|
var pipeline = context.SyntaxProvider.ForAttributeWithMetadataName("Ryujinx.HLE.HOS.Services.ServiceAttribute",
|
|
predicate: (node, _) => node is ClassDeclarationSyntax decl && !decl.Modifiers.Any(SyntaxKind.AbstractKeyword) && !decl.Modifiers.Any(SyntaxKind.PrivateKeyword),
|
|
transform: (ctx, _) =>
|
|
{
|
|
var target = (INamedTypeSymbol)ctx.TargetSymbol;
|
|
var instances = ctx.Attributes.Select(attr =>
|
|
{
|
|
string param = attr.ConstructorArguments is [_, { IsNull: false } arg] ? arg.ToCSharpString() : null;
|
|
return ((string)attr.ConstructorArguments[0].Value, param);
|
|
});
|
|
return new ServiceData
|
|
{
|
|
FullName = target.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat),
|
|
Instances = instances.ToList(),
|
|
};
|
|
}
|
|
);
|
|
|
|
context.RegisterSourceOutput(pipeline.Collect(),
|
|
(ctx, data) =>
|
|
{
|
|
var generator = new CodeGenerator();
|
|
|
|
generator.AppendLine("#nullable enable");
|
|
generator.AppendLine("using System;");
|
|
generator.EnterScope("namespace Ryujinx.HLE.HOS.Services.Sm");
|
|
generator.EnterScope("partial class IUserInterface");
|
|
|
|
generator.EnterScope("public IpcService? GetServiceInstance(string name, ServiceCtx context)");
|
|
|
|
generator.EnterScope("return name switch");
|
|
|
|
foreach (var serviceImpl in data)
|
|
{
|
|
foreach (var instance in serviceImpl.Instances)
|
|
{
|
|
if (instance.ParameterValue == null)
|
|
{
|
|
generator.AppendLine($"\"{instance.ServiceName}\" => new {serviceImpl.FullName}(context),");
|
|
}
|
|
else
|
|
{
|
|
generator.AppendLine($"\"{instance.ServiceName}\" => new {serviceImpl.FullName}(context, {instance.ParameterValue}),");
|
|
}
|
|
}
|
|
}
|
|
|
|
generator.AppendLine("_ => null,");
|
|
|
|
generator.LeaveScope(";");
|
|
|
|
generator.LeaveScope();
|
|
|
|
generator.LeaveScope();
|
|
generator.LeaveScope();
|
|
|
|
generator.AppendLine("#nullable disable");
|
|
|
|
ctx.AddSource("IUserInterface.g.cs", generator.ToString());
|
|
});
|
|
}
|
|
}
|
|
}
|