예제 #1
0
        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))))));
        }
        public override IEnumerable <MemberDeclarationSyntax> GenerateCode(CsCallable csElement)
        {
            // Documentation
            var documentationTrivia = GenerateDocumentationTrivia(csElement);

            // method signature
            var parameters = csElement.PublicParameters.Select(
                param => Generators.Marshalling.GetMarshaller(param)
                .GenerateManagedParameter(param)
                .WithDefault(param.DefaultValue == null
                                                    ? default
                                                    : EqualsValueClause(ParseExpression(param.DefaultValue))
                             )
                );

            var methodDeclaration = MethodDeclaration(
                ParseTypeName(csElement.GetPublicReturnTypeQualifiedName(globalNamespace)),
                csElement.Name
                )
                                    .WithModifiers(csElement.VisibilityTokenList.Add(Token(SyntaxKind.UnsafeKeyword)))
                                    .WithParameterList(ParameterList(SeparatedList(parameters)))
                                    .WithLeadingTrivia(Trivia(documentationTrivia));

            if (csElement.SignatureOnly)
            {
                yield return(methodDeclaration
                             .WithSemicolonToken(Token(SyntaxKind.SemicolonToken))
                             .WithModifiers(TokenList()));

                yield break;
            }

            var statements = new List <StatementSyntax>();

            foreach (var param in csElement.Parameters)
            {
                if ((param.Relations?.Count ?? 0) == 0)
                {
                    if (param.UsedAsReturn)
                    {
                        statements.Add(GenerateManagedHiddenMarshallableProlog(param));
                    }
                    statements.AddRange(Generators.Marshalling.GetMarshaller(param).GenerateManagedToNativeProlog(param));
                }
                else
                {
                    statements.Add(GenerateManagedHiddenMarshallableProlog(param));

                    foreach (var relation in param.Relations)
                    {
                        if (!ValidRelationInScenario(relation))
                        {
                            logger.Error(LoggingCodes.InvalidRelationInScenario, $"The relation \"{relation}\" is invalid in a method/function.");
                            continue;
                        }

                        var             marshaller = Generators.Marshalling.GetRelationMarshaller(relation);
                        StatementSyntax marshalToNative;
                        var             relatedMarshallableName = (relation as LengthRelation)?.Identifier;
                        if (relatedMarshallableName is null)
                        {
                            marshalToNative = marshaller.GenerateManagedToNative(null, param);
                        }
                        else
                        {
                            var relatedParameter = csElement.Parameters.SingleOrDefault(p => p.CppElementName == relatedMarshallableName);

                            if (relatedParameter is null)
                            {
                                logger.Error(LoggingCodes.InvalidRelationInScenario, $"The relation with \"{relatedMarshallableName}\" parameter is invalid in a method/function \"{csElement.Name}\".");
                                continue;
                            }

                            marshalToNative = marshaller.GenerateManagedToNative(relatedParameter, param);
                        }

                        if (marshalToNative != null)
                        {
                            statements.Add(marshalToNative);
                        }
                    }

                    statements.AddRange(Generators.Marshalling.GetMarshaller(param).GenerateManagedToNativeProlog(param));
                }
            }

            if (csElement.HasReturnType)
            {
                statements.Add(GenerateManagedHiddenMarshallableProlog(csElement.ReturnValue));
                statements.AddRange(
                    Generators.Marshalling.GetMarshaller(csElement.ReturnValue)
                    .GenerateManagedToNativeProlog(csElement.ReturnValue));
            }

            foreach (var param in csElement.Parameters)
            {
                if (param.IsIn || param.IsRefIn || param.IsRef)
                {
                    var marshaller      = Generators.Marshalling.GetMarshaller(param);
                    var marshalToNative = marshaller.GenerateManagedToNative(param, true);
                    if (marshalToNative != null)
                    {
                        statements.Add(marshalToNative);
                    }
                }
            }

            var fixedStatements = csElement.PublicParameters
                                  .Select(param => Generators.Marshalling.GetMarshaller(param).GeneratePin(param))
                                  .Where(stmt => stmt != null).ToList();

            var callStmt = GeneratorHelpers.GetPlatformSpecificStatements(
                globalNamespace, Generators.Config, csElement.InteropSignatures.Keys,
                platform => ExpressionStatement(
                    Generators.NativeInvocation.GenerateCall(
                        csElement, platform, csElement.InteropSignatures[platform]
                        )
                    )
                );

            var fixedStatement = fixedStatements.FirstOrDefault()?.WithStatement(callStmt);

            foreach (var statement in fixedStatements.Skip(1))
            {
                fixedStatement = statement.WithStatement(fixedStatement);
            }

            statements.Add(fixedStatement ?? callStmt);

            foreach (var param in csElement.Parameters)
            {
                if (param.IsRef || param.IsOut)
                {
                    var marshaller        = Generators.Marshalling.GetMarshaller(param);
                    var marshalFromNative = marshaller.GenerateNativeToManaged(param, true);
                    if (marshalFromNative != null)
                    {
                        statements.Add(marshalFromNative);
                    }
                }
            }

            if (csElement.HasReturnType)
            {
                var marshaller        = Generators.Marshalling.GetMarshaller(csElement.ReturnValue);
                var marshalReturnType = marshaller.GenerateNativeToManaged(csElement.ReturnValue, true);
                if (marshalReturnType != null)
                {
                    statements.Add(marshalReturnType);
                }
            }

            statements.AddRange(csElement.Parameters
                                .Where(param => !param.IsOut)
                                .Select(param => Generators.Marshalling.GetMarshaller(param).GenerateNativeCleanup(param, true))
                                .Where(param => param != null));


            if (csElement.IsReturnTypeResult(globalNamespace) && csElement.CheckReturnType)
            {
                statements.Add(ExpressionStatement(
                                   InvocationExpression(
                                       MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
                                                              IdentifierName(csElement.ReturnValue.Name),
                                                              IdentifierName("CheckError")))));
            }

            // Return
            if (csElement.HasReturnStatement(globalNamespace))
            {
                statements.Add(ReturnStatement(IdentifierName(csElement.ReturnName)));
            }

            yield return(methodDeclaration.WithBody(Block(statements)));
        }
예제 #3
0
        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)));
        }