public IEnumerable <MemberDeclarationSyntax> GenerateCode(CsFunction csElement)
        {
            foreach (var member in Generators.Callable.GenerateCode(csElement))
            {
                yield return(member);
            }

            foreach (var sig in csElement.InteropSignatures)
            {
                yield return(MethodDeclaration(ParseTypeName(sig.Value.ReturnType.TypeName), $"{csElement.CppElementName}{GeneratorHelpers.GetPlatformSpecificSuffix(sig.Key)}")
                             .WithModifiers(
                                 TokenList(
                                     Token(SyntaxKind.PrivateKeyword),
                                     Token(SyntaxKind.UnsafeKeyword),
                                     Token(SyntaxKind.StaticKeyword),
                                     Token(SyntaxKind.ExternKeyword)))
                             .WithAttributeLists(SingletonList(AttributeList(SingletonSeparatedList(
                                                                                 Attribute(
                                                                                     QualifiedName(
                                                                                         QualifiedName(
                                                                                             QualifiedName(
                                                                                                 IdentifierName("System"),
                                                                                                 IdentifierName("Runtime")),
                                                                                             IdentifierName("InteropServices")),
                                                                                         IdentifierName("DllImportAttribute")))
                                                                                 .WithArgumentList(
                                                                                     AttributeArgumentList(
                                                                                         SeparatedList(
                                                                                             new[]
                {
                    AttributeArgument(
                        IdentifierName(csElement.DllName)),
                    AttributeArgument(
                        LiteralExpression(
                            SyntaxKind.StringLiteralExpression,
                            Literal(csElement.CppElementName)))
                    .WithNameEquals(
                        NameEquals(
                            IdentifierName("EntryPoint"))),
                    AttributeArgument(
                        MemberAccessExpression(
                            SyntaxKind.SimpleMemberAccessExpression,
                            MemberAccessExpression(
                                SyntaxKind.SimpleMemberAccessExpression,
                                MemberAccessExpression(
                                    SyntaxKind.SimpleMemberAccessExpression,
                                    MemberAccessExpression(
                                        SyntaxKind.SimpleMemberAccessExpression,
                                        IdentifierName("System"),
                                        IdentifierName("Runtime")),
                                    IdentifierName("InteropServices")),
                                IdentifierName("CallingConvention")),
                            IdentifierName(csElement.CppCallingConvention.ToManagedCallingConventionName())))
                    .WithNameEquals(
                        NameEquals(
                            IdentifierName("CallingConvention")))
                })))))))
                             .WithParameterList(ParameterList(SeparatedList(
                                                                  sig.Value.ParameterTypes.Select(param =>
                                                                                                  Parameter(Identifier(param.Name))
                                                                                                  .WithType(param.InteropTypeSyntax)))))
                             .WithSemicolonToken(Token(SyntaxKind.SemicolonToken)));
            }
        }
 private DelegateDeclarationSyntax GenerateDelegateDeclaration(CsCallable csElement, PlatformDetectionType platform, InteropMethodSignature sig)
 {
     return(DelegateDeclaration(ParseTypeName(sig.ReturnType.TypeName), $"{csElement.Name}Delegate{GeneratorHelpers.GetPlatformSpecificSuffix(platform)}")
            .AddAttributeLists(
                AttributeList(
                    SingletonSeparatedList(
                        Attribute(
                            ParseName("System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute"))
                        .AddArgumentListArguments(
                            AttributeArgument(
                                MemberAccessExpression(
                                    SyntaxKind.SimpleMemberAccessExpression,
                                    MemberAccessExpression(
                                        SyntaxKind.SimpleMemberAccessExpression,
                                        MemberAccessExpression(
                                            SyntaxKind.SimpleMemberAccessExpression,
                                            MemberAccessExpression(
                                                SyntaxKind.SimpleMemberAccessExpression,
                                                IdentifierName("System"),
                                                IdentifierName("Runtime")),
                                            IdentifierName("InteropServices")),
                                        IdentifierName("CallingConvention")),
                                    IdentifierName(sig.CallingConvention)))))))
            .WithParameterList(
                ParameterList(
                    (csElement is CsMethod ?
                     SingletonSeparatedList(
                         Parameter(Identifier("thisObject"))
                         .WithType(ParseTypeName("System.IntPtr")))
                 : default)
        public MemberDeclarationSyntax GenerateCode(CsInterface csElement)
        {
            var vtblClassName = csElement.VtblName.Split('.').Last();

            return(ClassDeclaration(vtblClassName)
                   .WithModifiers(
                       TokenList(
                           Token(SyntaxKind.ProtectedKeyword),
                           Token(SyntaxKind.UnsafeKeyword)))
                   .WithBaseList(
                       BaseList(
                           SingletonSeparatedList <BaseTypeSyntax>(
                               SimpleBaseType(
                                   csElement.Base != null ?
                                   (NameSyntax)IdentifierName(csElement.Base.VtblName)
                                    : globalNamespace.GetTypeNameSyntax(WellKnownName.CppObjectVtbl)))))
                   .WithMembers(
                       List(
                           new MemberDeclarationSyntax[]
            {
                ConstructorDeclaration(
                    Identifier(vtblClassName))
                .WithModifiers(
                    TokenList(
                        Token(SyntaxKind.PublicKeyword)))
                .WithParameterList(
                    ParameterList(
                        SingletonSeparatedList(
                            Parameter(
                                Identifier("numberOfCallbackMethods"))
                            .WithType(
                                PredefinedType(
                                    Token(SyntaxKind.IntKeyword))))))
                .WithInitializer(
                    ConstructorInitializer(
                        SyntaxKind.BaseConstructorInitializer,
                        ArgumentList(
                            SingletonSeparatedList(
                                Argument(
                                    BinaryExpression(
                                        SyntaxKind.AddExpression,
                                        IdentifierName("numberOfCallbackMethods"),
                                        LiteralExpression(
                                            SyntaxKind.NumericLiteralExpression,
                                            Literal(csElement.Methods.Count()))))))))
                .WithBody(
                    Block(csElement.Methods
                          .OrderBy(method => method.Offset)
                          .Select(method => GeneratorHelpers.GetPlatformSpecificStatements(globalNamespace, generators.Config, method.InteropSignatures.Keys,
                                                                                           platform =>
                                                                                           ExpressionStatement(
                                                                                               InvocationExpression(
                                                                                                   IdentifierName("AddMethod"))
                                                                                               .WithArgumentList(
                                                                                                   ArgumentList(
                                                                                                       SeparatedList(
                                                                                                           new []
                {
                    Argument(
                        ObjectCreationExpression(
                            IdentifierName($"{method.Name}Delegate{GeneratorHelpers.GetPlatformSpecificSuffix(platform)}"))
                        .WithArgumentList(
                            ArgumentList(
                                SingletonSeparatedList(
                                    Argument(
                                        IdentifierName($"{method.Name}{GeneratorHelpers.GetPlatformSpecificSuffix(platform)}")))))),
                    Argument(
                        LiteralExpression(SyntaxKind.NumericLiteralExpression,
                                          Literal((platform & PlatformDetectionType.IsWindows) != 0 ? method.WindowsOffset : method.Offset)))
                }
                                                                                                           ))))))))
            }
                           .Concat(csElement.Methods
                                   .SelectMany(method => generators.ShadowCallable.GenerateCode(method))))));
        }
Exemple #4
0
        public ExpressionSyntax GenerateCall(CsCallable callable, PlatformDetectionType platform,
                                             InteropMethodSignature interopSig)
        {
            var arguments = IterateNativeArguments(callable, interopSig).ToArray();

            ElementAccessExpressionSyntax vtblAccess = null;

            if (callable is CsMethod method)
            {
                var windowsOffsetExpression =
                    LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(method.WindowsOffset));
                var nonWindowsOffsetExpression =
                    LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(method.Offset));

                ExpressionSyntax vtableOffsetExpression;
                if ((platform & PlatformDetectionType.Any) == PlatformDetectionType.Any &&
                    method.Offset != method.WindowsOffset)
                {
                    vtableOffsetExpression = ConditionalExpression(
                        MemberAccessExpression(
                            SyntaxKind.SimpleMemberAccessExpression,
                            GlobalNamespace.GetTypeNameSyntax(WellKnownName.PlatformDetection),
                            IdentifierName("Is" + nameof(PlatformDetectionType.Windows))),
                        windowsOffsetExpression,
                        nonWindowsOffsetExpression);
                }
                else if ((platform & PlatformDetectionType.Windows) != 0)
                {
                    vtableOffsetExpression = windowsOffsetExpression;
                }
                else
                {
                    vtableOffsetExpression = nonWindowsOffsetExpression;
                }

                vtblAccess = ElementAccessExpression(
                    ThisExpression(),
                    BracketedArgumentList(
                        SingletonSeparatedList(
                            Argument(
                                method.CustomVtbl
                                    ? MemberAccessExpression(
                                    SyntaxKind.SimpleMemberAccessExpression,
                                    ThisExpression(),
                                    IdentifierName($"{callable.Name}__vtbl_index")
                                    )
                                    : vtableOffsetExpression
                                )
                            )
                        )
                    );
            }

            ExpressionSyntax FnPtrCall()
            {
                var fnptrParameters = arguments
                                      .Select(x => x.Type)
                                      .Append(ParseTypeName(interopSig.ReturnType.TypeName))
                                      .Select(FunctionPointerParameter);

                return(GeneratorHelpers.CastExpression(
                           FunctionPointerType(
                               FunctionPointerCallingConvention(
                                   Token(SyntaxKind.UnmanagedKeyword),
                                   FunctionPointerUnmanagedCallingConventionList(
                                       SingletonSeparatedList(
                                           FunctionPointerUnmanagedCallingConvention(
                                               Identifier(callable.CppCallingConvention.ToCallConvShortName())
                                               )
                                           )
                                       )
                                   ),
                               FunctionPointerParameterList(SeparatedList(fnptrParameters))
                               ),
                           vtblAccess
                           ));
            }

            var what = callable switch
            {
                CsFunction => IdentifierName(
                    callable.CppElementName + GeneratorHelpers.GetPlatformSpecificSuffix(platform)
                    ),
                CsMethod => GeneratorHelpers.WrapInParentheses(FnPtrCall()),
                _ => throw new ArgumentOutOfRangeException()
            };

            ExpressionSyntax call = InvocationExpression(
                what,
                ArgumentList(SeparatedList(arguments.Select(x => x.Argument)))
                );

            if (interopSig.CastToNativeLong)
            {
                call = CastExpression(GlobalNamespace.GetTypeNameSyntax(WellKnownName.NativeLong), call);
            }

            if (interopSig.CastToNativeULong)
            {
                call = CastExpression(GlobalNamespace.GetTypeNameSyntax(WellKnownName.NativeULong), call);
            }

            if (interopSig.ForcedReturnBufferSig || !callable.HasReturnType)
            {
                return(call);
            }

            return(AssignmentExpression(
                       SyntaxKind.SimpleAssignmentExpression,
                       GetMarshaller(callable.ReturnValue).GeneratesMarshalVariable(callable.ReturnValue)
                    ? MarshallerBase.GetMarshalStorageLocation(callable.ReturnValue)
                    : IdentifierName(callable.ReturnValue.Name),
                       call
                       ));
        }
        public MemberDeclarationSyntax GenerateCode(CsInterface csElement)
        {
            var vtblClassName = csElement.VtblName.Split('.').Last();

            // Default: at least protected to enable inheritance.
            var vtblVisibility = csElement.VtblVisibility ?? Visibility.ProtectedInternal;

            StatementSyntax VtblMethodSelector(CsMethod method)
            {
                StatementSyntax MethodBuilder(PlatformDetectionType platform)
                {
                    var arguments = new[]
                    {
                        Argument(
                            ObjectCreationExpression(IdentifierName(GetMethodDelegateName(method, platform)))
                            .WithArgumentList(
                                ArgumentList(
                                    SingletonSeparatedList(
                                        Argument(
                                            IdentifierName(
                                                $"{method.Name}{GeneratorHelpers.GetPlatformSpecificSuffix(platform)}"
                                                )
                                            )
                                        )
                                    )
                                )
                            ),
                        Argument(
                            LiteralExpression(
                                SyntaxKind.NumericLiteralExpression,
                                Literal((platform & PlatformDetectionType.Windows) != 0
                                            ? method.WindowsOffset
                                            : method.Offset)
                                )
                            )
                    };

                    return(ExpressionStatement(
                               InvocationExpression(IdentifierName("AddMethod"))
                               .WithArgumentList(ArgumentList(SeparatedList(arguments)))
                               ));
                }

                return(GeneratorHelpers.GetPlatformSpecificStatements(GlobalNamespace, Generators.Config,
                                                                      method.InteropSignatures.Keys, MethodBuilder));
            }

            List <MemberDeclarationSyntax> members = new()
            {
                ConstructorDeclaration(Identifier(vtblClassName))
                .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword)))
                .WithParameterList(
                    ParameterList(
                        SingletonSeparatedList(
                            Parameter(Identifier("numberOfCallbackMethods"))
                            .WithType(PredefinedType(Token(SyntaxKind.IntKeyword)))
                            )
                        )
                    )
                .WithInitializer(
                    ConstructorInitializer(
                        SyntaxKind.BaseConstructorInitializer,
                        ArgumentList(
                            SingletonSeparatedList(
                                Argument(
                                    BinaryExpression(
                                        SyntaxKind.AddExpression,
                                        IdentifierName("numberOfCallbackMethods"),
                                        LiteralExpression(
                                            SyntaxKind.NumericLiteralExpression,
                                            Literal(csElement.MethodList.Count)
                                            )
                                        )
                                    )
                                )
                            )
                        )
                    )
                .WithBody(
                    Block(
                        csElement.Methods
                        .OrderBy(method => method.Offset)
                        .Select(VtblMethodSelector)
                        )
                    )
            };

            members.AddRange(csElement.Methods.SelectMany(method => Generators.ShadowCallable.GenerateCode(method)));

            return(ClassDeclaration(vtblClassName)
                   .WithModifiers(
                       ModelUtilities.VisibilityToTokenList(vtblVisibility, SyntaxKind.UnsafeKeyword,
                                                            SyntaxKind.PartialKeyword)
                       )
                   .WithAttributeLists(DebuggerTypeProxyAttribute)
                   .WithBaseList(
                       BaseList(
                           SingletonSeparatedList <BaseTypeSyntax>(
                               SimpleBaseType(
                                   csElement.Base != null
                                       ? IdentifierName(csElement.Base.VtblName)
                                       : GlobalNamespace.GetTypeNameSyntax(WellKnownName.CppObjectVtbl)
                                   )
                               )
                           )
                       )
                   .WithMembers(List(members)));
        }
 internal static string GetMethodDelegateName(CsCallable csElement, PlatformDetectionType platform) =>
 csElement.Name + "Delegate" + GeneratorHelpers.GetPlatformSpecificSuffix(platform);