diff options
Diffstat (limited to 'src/Ryujinx.HLE.Generators/IpcServiceGenerator.cs')
| -rw-r--r-- | src/Ryujinx.HLE.Generators/IpcServiceGenerator.cs | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/src/Ryujinx.HLE.Generators/IpcServiceGenerator.cs b/src/Ryujinx.HLE.Generators/IpcServiceGenerator.cs new file mode 100644 index 00000000..19fdbe19 --- /dev/null +++ b/src/Ryujinx.HLE.Generators/IpcServiceGenerator.cs @@ -0,0 +1,76 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.Linq; + +namespace Ryujinx.HLE.Generators +{ + [Generator] + public class IpcServiceGenerator : ISourceGenerator + { + public void Execute(GeneratorExecutionContext context) + { + var syntaxReceiver = (ServiceSyntaxReceiver)context.SyntaxReceiver; + CodeGenerator generator = new CodeGenerator(); + + generator.AppendLine("using System;"); + generator.EnterScope($"namespace Ryujinx.HLE.HOS.Services.Sm"); + generator.EnterScope($"partial class IUserInterface"); + + generator.EnterScope($"public IpcService? GetServiceInstance(Type type, ServiceCtx context, object? parameter = null)"); + foreach (var className in syntaxReceiver.Types) + { + if (className.Modifiers.Any(SyntaxKind.AbstractKeyword) || className.Modifiers.Any(SyntaxKind.PrivateKeyword) || !className.AttributeLists.Any(x => x.Attributes.Any(y => y.ToString().StartsWith("Service")))) + continue; + var name = GetFullName(className, context).Replace("global::", ""); + if (!name.StartsWith("Ryujinx.HLE.HOS.Services")) + continue; + var constructors = className.ChildNodes().Where(x => x.IsKind(SyntaxKind.ConstructorDeclaration)).Select(y => y as ConstructorDeclarationSyntax); + + if (!constructors.Any(x => x.ParameterList.Parameters.Count >= 1)) + continue; + + if (constructors.Where(x => x.ParameterList.Parameters.Count >= 1).FirstOrDefault().ParameterList.Parameters[0].Type.ToString() == "ServiceCtx") + { + generator.EnterScope($"if (type == typeof({GetFullName(className, context)}))"); + if (constructors.Any(x => x.ParameterList.Parameters.Count == 2)) + { + var type = constructors.Where(x => x.ParameterList.Parameters.Count == 2).FirstOrDefault().ParameterList.Parameters[1].Type; + var model = context.Compilation.GetSemanticModel(type.SyntaxTree); + var typeSymbol = model.GetSymbolInfo(type).Symbol as INamedTypeSymbol; + var fullName = typeSymbol.ToString(); + generator.EnterScope("if (parameter != null)"); + generator.AppendLine($"return new {GetFullName(className, context)}(context, ({fullName})parameter);"); + generator.LeaveScope(); + } + + if (constructors.Any(x => x.ParameterList.Parameters.Count == 1)) + { + generator.AppendLine($"return new {GetFullName(className, context)}(context);"); + } + + generator.LeaveScope(); + } + } + + generator.AppendLine("return null;"); + generator.LeaveScope(); + + generator.LeaveScope(); + generator.LeaveScope(); + context.AddSource($"IUserInterface.g.cs", generator.ToString()); + } + + private string GetFullName(ClassDeclarationSyntax syntaxNode, GeneratorExecutionContext context) + { + var typeSymbol = context.Compilation.GetSemanticModel(syntaxNode.SyntaxTree).GetDeclaredSymbol(syntaxNode); + + return typeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); + } + + public void Initialize(GeneratorInitializationContext context) + { + context.RegisterForSyntaxNotifications(() => new ServiceSyntaxReceiver()); + } + } +} |
