Beispiel #1
0
    protected override ExpressionSyntax Generate(CsCallable callable, PlatformDetectionType platform)
    {
        var interopSig        = callable.InteropSignatures[platform];
        var interopReturnType = interopSig.ReturnTypeSyntax;
        var arguments         = IterateNativeArguments(callable is CsMethod, interopSig).ToArray();

        var vtblAccess = callable switch
        {
            CsMethod method => ElementAccessExpression(
                ThisExpression(),
                BracketedArgumentList(
                    SingletonSeparatedList(
                        Argument(
                            method.CustomVtbl
                                ? MemberAccessExpression(
                                SyntaxKind.SimpleMemberAccessExpression,
                                ThisExpression(),
                                IdentifierName($"{callable.Name}__vtbl_index")
                                )
                                : method.VTableOffsetExpression(platform)
                            )
                        )
                    )
                ),
            _ => null
        };

        ExpressionSyntax FnPtrCall()
        {
            var fnptrParameters = arguments
                                  .Select(x => x.Type)
                                  .Append(interopReturnType)
                                  .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.ForcedReturnBufferSig || !callable.HasReturnType)
        {
            return(call);
        }

        var generatesMarshalVariable = GetMarshaller(callable.ReturnValue).GeneratesMarshalVariable(callable.ReturnValue);
        var publicTypeSyntax         = ReverseCallablePrologCodeGenerator.GetPublicType(callable.ReturnValue);

        if (callable.HasReturnTypeValue && !generatesMarshalVariable && !publicTypeSyntax.IsEquivalentTo(interopSig.ReturnTypeSyntax))
        {
            call = CastExpression(publicTypeSyntax, call);
        }

        return(AssignmentExpression(
                   SyntaxKind.SimpleAssignmentExpression,
                   generatesMarshalVariable
                ? MarshallerBase.GetMarshalStorageLocation(callable.ReturnValue)
                : IdentifierName(callable.ReturnValue.Name),
                   call
                   ));
    }