예제 #1
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)));
        }
예제 #2
0
 internal static string GetMethodDelegateName(CsCallable csElement, PlatformDetectionType platform) =>
 csElement.Name + "Delegate" + GeneratorHelpers.GetPlatformSpecificSuffix(platform);
예제 #3
0
        public override IEnumerable <MemberDeclarationSyntax> GenerateCode(CsField csElement)
        {
            if (csElement.IsBoolToInt && !csElement.IsArray)
            {
                yield return(GenerateBackingField(csElement, csElement.MarshalType));

                yield return(GenerateProperty(
                                 csElement, PredefinedType(Token(SyntaxKind.BoolKeyword)),
                                 GeneratorHelpers.GenerateIntToBoolConversion,
                                 (_, value) => GeneratorHelpers.CastExpression(
                                     ParseTypeName(csElement.MarshalType.QualifiedName),
                                     GeneratorHelpers.GenerateBoolToIntConversion(value)
                                     )
                                 ));
            }
            else if (csElement.IsArray && !csElement.IsString)
            {
                var elementType = ParseTypeName(csElement.PublicType.QualifiedName);

                yield return(GenerateBackingField(csElement, csElement.PublicType, isArray: true));

                yield return(GenerateProperty(
                                 csElement, ArrayType(elementType, SingletonList(ArrayRankSpecifier())),
                                 value => AssignmentExpression(
                                     SyntaxKind.CoalesceAssignmentExpression,
                                     value,
                                     ObjectCreationExpression(
                                         ArrayType(
                                             elementType,
                                             SingletonList(
                                                 ArrayRankSpecifier(
                                                     SingletonSeparatedList <ExpressionSyntax>(
                                                         LiteralExpression(
                                                             SyntaxKind.NumericLiteralExpression,
                                                             Literal(csElement.ArrayDimensionValue)
                                                             )
                                                         )
                                                     )
                                                 )
                                             )
                                         )
                                     ),
                                 null
                                 ));
            }
            else if (csElement.IsBitField)
            {
                PropertyValueGetTransform getterTransform;
                PropertyValueSetTransform setterTransform;
                TypeSyntax propertyType;

                if (csElement.IsBoolBitField)
                {
                    getterTransform = GeneratorHelpers.GenerateIntToBoolConversion;
                    setterTransform = (_, value) => GeneratorHelpers.GenerateBoolToIntConversion(value);
                    propertyType    = PredefinedType(Token(SyntaxKind.BoolKeyword));
                }
                else
                {
                    getterTransform = valueExpression => GeneratorHelpers.CastExpression(
                        ParseTypeName(csElement.PublicType.QualifiedName),
                        valueExpression
                        );
                    setterTransform = null;
                    propertyType    = ParseTypeName(csElement.PublicType.QualifiedName);
                }

                yield return(GenerateBackingField(csElement, csElement.PublicType));

                var bitMask   = LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(csElement.BitMask));
                var bitOffset = LiteralExpression(
                    SyntaxKind.NumericLiteralExpression, Literal(csElement.BitOffset)
                    );

                yield return(GenerateProperty(
                                 csElement, propertyType,
                                 Compose(
                                     getterTransform,
                                     value => BinaryExpression(
                                         SyntaxKind.BitwiseAndExpression,
                                         GeneratorHelpers.WrapInParentheses(
                                             BinaryExpression(SyntaxKind.RightShiftExpression, value, bitOffset)
                                             ),
                                         bitMask
                                         )
                                     ),
                                 Compose(
                                     (oldValue, value) => GeneratorHelpers.CastExpression(
                                         ParseTypeName(csElement.PublicType.QualifiedName),
                                         BinaryExpression(
                                             SyntaxKind.BitwiseOrExpression,
                                             GeneratorHelpers.WrapInParentheses(
                                                 BinaryExpression(
                                                     SyntaxKind.BitwiseAndExpression,
                                                     oldValue,
                                                     PrefixUnaryExpression(
                                                         SyntaxKind.BitwiseNotExpression,
                                                         GeneratorHelpers.WrapInParentheses(
                                                             BinaryExpression(SyntaxKind.LeftShiftExpression, bitMask, bitOffset)
                                                             )
                                                         )
                                                     )
                                                 ),
                                             GeneratorHelpers.WrapInParentheses(
                                                 BinaryExpression(
                                                     SyntaxKind.LeftShiftExpression,
                                                     GeneratorHelpers.WrapInParentheses(
                                                         BinaryExpression(SyntaxKind.BitwiseAndExpression, value, bitMask)
                                                         ),
                                                     bitOffset
                                                     )
                                                 )
                                             )
                                         ),
                                     setterTransform
                                     )
                                 ));
            }
            else
            {
                yield return(GenerateBackingField(
                                 csElement, csElement.PublicType, propertyBacking: false, document: true
                                 ));
            }
        }
예제 #4
0
        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.CallingConvention)))
                                                .WithNameEquals(
                                                    NameEquals(
                                                        IdentifierName("CallingConvention")))
                                        })))))))
                    .WithParameterList(ParameterList(SeparatedList(
                        sig.Value.ParameterTypes.Select((param, i) =>
                            Parameter(Identifier($"param{i}"))
                                .WithType(ParseTypeName(param.TypeName))))))
                    .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 override IEnumerable <MemberDeclarationSyntax> GenerateCode(CsCallable csElement)
        {
            // Documentation
            var documentationTrivia = GenerateDocumentationTrivia(csElement);

            // method signature
            var methodDeclaration = MethodDeclaration(ParseTypeName(csElement.PublicReturnTypeQualifiedName), csElement.Name)
                                    .WithModifiers(TokenList(ParseTokens(csElement.VisibilityName)).Add(Token(SyntaxKind.UnsafeKeyword)))
                                    .WithParameterList(
                ParameterList(
                    SeparatedList(
                        csElement.PublicParameters.Select(param =>
                                                          Generators.Marshalling.GetMarshaller(param).GenerateManagedParameter(param)
                                                          .WithDefault(param.DefaultValue == null ? default
                                        : EqualsValueClause(ParseExpression(param.DefaultValue)))
                                                          )
                        )
                    )
                )
                                    .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.Find(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.GenerateCode((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.ReturnValue.PublicType.Name == globalNamespace.GetTypeName(WellKnownName.Result)) && csElement.CheckReturnType)
            {
                statements.Add(ExpressionStatement(
                                   InvocationExpression(
                                       MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
                                                              IdentifierName(csElement.ReturnValue.Name),
                                                              IdentifierName("CheckError")))));
            }

            // Return
            if (csElement.HasPublicReturnType)
            {
                if (csElement.HasReturnTypeParameter || csElement.ForceReturnType || !csElement.HideReturnType)
                {
                    statements.Add(ReturnStatement(IdentifierName(csElement.ReturnName)));
                }
            }

            yield return(methodDeclaration.WithBody(Block(statements)));
        }