예제 #1
0
        private ParameterSyntax BuildParameter(CppParameter cppParameter, bool convertConstCharPtr, bool useFunctionPointers = false)
        {
            var name = Identifier(GetManagedName(cppParameter.Name));

            if (TypeMap.TryResolveType(cppParameter.Type, out var typeInfo))
            {
                if (convertConstCharPtr && typeInfo.CppType.IsConstCharPtr())
                {
                    return(Parameter(name)
                           .WithType(SyntaxBuilder.BuildReadOnlySpanName(SyntaxKind.CharKeyword))
                           .AddModifiers(Token(SyntaxKind.InKeyword)));
                }

                if (useFunctionPointers && typeInfo.IsFunction)
                {
                    return(Parameter(name).WithType(SyntaxBuilder.IntPtrName));
                }

                return(Parameter(name).WithType(typeInfo.TypeSyntax));
            }

            if (Debugger.IsAttached)
            {
                Debugger.Break();
            }
            throw new NotSupportedException();
        }
예제 #2
0
        private MemberDeclarationSyntax BuildField(CppField cppField)
        {
            if (TypeMap.TryResolveType(cppField.Type, out var typeInfo))
            {
                if (typeInfo.IsFunction)
                {
                    return(FieldDeclaration(
                               VariableDeclaration(IdentifierName(nameof(IntPtr)))
                               .AddVariables(VariableDeclarator(cppField.Name)))
                           .AddModifiers(Token(SyntaxKind.PublicKeyword))
                           .AddManagedTypeAttribute(typeInfo.TypeSyntax));
                }

                return(FieldDeclaration(
                           VariableDeclaration(typeInfo.TypeSyntax)
                           .AddVariables(VariableDeclarator(cppField.Name)))
                       .AddModifiers(Token(SyntaxKind.PublicKeyword)));
            }

            if (Debugger.IsAttached)
            {
                Debugger.Break();
            }
            throw new NotImplementedException();
        }
예제 #3
0
        private IEnumerable <StatementSyntax> BuildBaseMethodBody(CppFunction cppFunction, TypeInfo returnTypeInfo)
        {
            yield return(SyntaxBuilder.DeclareLocals(false));

            var functionPointer = IdentifierName(GetManagedName(cppFunction.Name + "Ptr"));

            yield return(SyntaxBuilder.CallGuard(functionPointer));

            IdentifierNameSyntax result = null;

            if (!returnTypeInfo.IsVoid)
            {
                if (returnTypeInfo.IsFunction)
                {
                    yield return(SyntaxBuilder.DeclareResultVariable(SyntaxBuilder.IntPtrName, out result));
                }
                else
                {
                    yield return(SyntaxBuilder.DeclareResultVariable(returnTypeInfo.TypeSyntax, out result));
                }
            }

            var delegates = new Dictionary <string, string>();

            foreach (var cppParameter in cppFunction.Parameters)
            {
                if (TypeMap.TryResolveType(cppParameter.Type, out var typeInfo) && typeInfo.IsFunction)
                {
                    delegates.Add(cppParameter.Name, null);
                }
                yield return(SyntaxBuilder.EmitPush(IdentifierName(GetManagedName(cppParameter.Name))));
            }

            yield return(SyntaxBuilder.EmitPush(functionPointer));

            yield return(SyntaxBuilder.EmitCalli(returnTypeInfo, cppFunction, TypeMap, delegates));

            if (result != null)
            {
                yield return(SyntaxBuilder.EmitPop(result));

                if (returnTypeInfo.IsFunction)
                {
                    yield return(ReturnStatement(
                                     InvocationExpression(
                                         MemberAccessExpression(
                                             SyntaxKind.SimpleMemberAccessExpression,
                                             IdentifierName(nameof(Marshal)),
                                             GenericName(nameof(Marshal.GetDelegateForFunctionPointer))
                                             .AddTypeArgumentListArguments(returnTypeInfo.TypeSyntax)))
                                     .AddArgumentListArguments(Argument(result))));
                }
                else
                {
                    yield return(ReturnStatement(result));
                }
            }
        }
예제 #4
0
        private IEnumerable <MemberDeclarationSyntax> BuildFunctions(CppFunction cppFunction)
        {
            Log.WriteLine($"Building function '{GetManagedName(cppFunction.Name)}' from '{cppFunction.Name}'.",
                          ConsoleColor.DarkGray);

            if (!TypeMap.TryResolveType(cppFunction.ReturnType, out var returnTypeInfo))
            {
                throw new ArgumentException();
            }

            MethodDeclarationSyntax method;

            if (HasFunctionParameters(cppFunction))
            {
                method = MethodDeclaration(returnTypeInfo.TypeSyntax, GetManagedName(cppFunction.Name) + "Private")
                         .AddModifiers(Token(SyntaxKind.PrivateKeyword), Token(SyntaxKind.StaticKeyword))
                         .AddParameterListParameters(cppFunction.Parameters.Select(p => BuildParameter(p, false, true)).ToArray())
                         .AddAggressiveInlining()
                         .WithBody(Block(BuildBaseMethodBody(cppFunction, returnTypeInfo)))
                         .AddUnsafeIfNeeded();

                yield return(method);

                method = MethodDeclaration(returnTypeInfo.TypeSyntax, GetManagedName(cppFunction.Name))
                         .AddModifiers(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.StaticKeyword))
                         .AddParameterListParameters(cppFunction.Parameters.Select(p => BuildParameter(p, false)).ToArray())
                         .AddAggressiveInlining()
                         .WithBody(Block(BuildDelegateBody(cppFunction, returnTypeInfo)))
                         .AddUnsafeIfNeeded();
            }
            else
            {
                method = MethodDeclaration(returnTypeInfo.TypeSyntax, GetManagedName(cppFunction.Name))
                         .AddModifiers(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.StaticKeyword))
                         .AddParameterListParameters(cppFunction.Parameters.Select(p => BuildParameter(p, false)).ToArray())
                         .AddAggressiveInlining()
                         .WithBody(Block(BuildBaseMethodBody(cppFunction, returnTypeInfo)))
                         .AddUnsafeIfNeeded();
            }

            method = method.AddDocumentationComments(cppFunction.Comment, cppFunction.Name);
            yield return(method);

            if (cppFunction.Parameters.Any(p => p.Type.IsConstCharPtr()))
            {
                method = MethodDeclaration(returnTypeInfo.TypeSyntax, GetManagedName(cppFunction.Name))
                         .AddModifiers(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.StaticKeyword), Token(SyntaxKind.UnsafeKeyword))
                         .AddParameterListParameters(cppFunction.Parameters.Select(p => BuildParameter(p, true)).ToArray())
                         .AddAggressiveInlining()
                         .WithBody(Block(BuildStringBody(cppFunction, returnTypeInfo)));
                method = method.AddDocumentationComments(cppFunction.Comment, cppFunction.Name);
                yield return(method);
            }

            Log.WriteLine("Done.", ConsoleColor.DarkGreen);
        }
예제 #5
0
        private bool HasFunctionParameters(CppFunction cppFunction)
        {
            foreach (var cppParameter in cppFunction.Parameters)
            {
                if (TypeMap.TryResolveType(cppParameter.Type, out var typeInfo) && typeInfo.IsFunction)
                {
                    return(true);
                }
            }

            return(false);
        }
예제 #6
0
        public static ExpressionStatementSyntax EmitCalli(TypeInfo returnTypeInfo, CppFunction cppFunction,
                                                          TypeMap typeMap, IReadOnlyDictionary <string, string> delegates)
        {
            return(ExpressionStatement(
                       InvocationExpression(
                           MemberAccessExpression(
                               SyntaxKind.SimpleMemberAccessExpression,
                               MemberAccessExpression(
                                   SyntaxKind.SimpleMemberAccessExpression,
                                   IdentifierName("IL"),
                                   IdentifierName("Emit")),
                               IdentifierName("Calli")),
                           ArgumentList(SingletonSeparatedList(Argument(
                                                                   ObjectCreationExpression(
                                                                       IdentifierName("StandAloneMethodSig"),
                                                                       ArgumentList(SeparatedList(GetMethodSigParameters())),
                                                                       null)))))));

            IEnumerable <ArgumentSyntax> GetMethodSigParameters()
            {
                yield return(Argument(
                                 MemberAccessExpression(
                                     SyntaxKind.SimpleMemberAccessExpression,
                                     IdentifierName(nameof(CallingConvention)),
                                     IdentifierName(nameof(CallingConvention.Cdecl)))));

                if (returnTypeInfo.IsFunction)
                {
                    yield return(Argument(TypeOfExpression(IntPtrName)));
                }
                else
                {
                    yield return(Argument(TypeOfExpression(returnTypeInfo.TypeSyntax)));
                }

                foreach (var cppParameter in cppFunction.Parameters)
                {
                    if (delegates.TryGetValue(cppParameter.Name, out _))
                    {
                        yield return(Argument(TypeOfExpression(IdentifierName(nameof(IntPtr)))));
                    }
                    else if (typeMap.TryResolveType(cppParameter.Type, out var paramTypeInfo))
                    {
                        yield return(Argument(TypeOfExpression(paramTypeInfo.TypeSyntax)));
                    }
                    else
                    {
                        throw new ArgumentException();
                    }
                }
            }
        }
예제 #7
0
        private ParameterSyntax BuildParameter(CppParameter cppParameter)
        {
            var name = Identifier(cppParameter.Name);

            if (TypeMap.TryResolveType(cppParameter.Type, out var typeInfo))
            {
                return(Parameter(name).WithType(typeInfo.TypeSyntax));
            }

            if (Debugger.IsAttached)
            {
                Debugger.Break();
            }
            throw new NotSupportedException();
        }
예제 #8
0
        private IEnumerable <StatementSyntax> BuildDelegateBody(CppFunction cppFunction, TypeInfo returnTypeInfo)
        {
            yield return(SyntaxBuilder.DeclareLocals(false));

            var delegates = new Dictionary <string, string>();

            foreach (var cppParameter in cppFunction.Parameters)
            {
                if (!TypeMap.TryResolveType(cppParameter.Type, out var paramTypeInfo, false))
                {
                    throw new ArgumentException();
                }

                if (!paramTypeInfo.IsFunction)
                {
                    continue;
                }

                var managedParameterName = GetManagedName(cppParameter.Name);
                var variableName         = managedParameterName + "Ptr";
                delegates.Add(cppParameter.Name, variableName);
                yield return(SyntaxBuilder.DeclareDelegatePointerVariable(managedParameterName, variableName));
            }

            var call =
                InvocationExpression(IdentifierName(GetManagedName(cppFunction.Name) + "Private"))
                .AddArgumentListArguments(cppFunction.Parameters.Select(BuildArgument).ToArray());

            if (returnTypeInfo.IsVoid)
            {
                yield return(ExpressionStatement(call));
            }
            else
            {
                yield return(LocalDeclarationStatement(
                                 VariableDeclaration(returnTypeInfo.TypeSyntax)
                                 .AddVariables(VariableDeclarator("result").WithInitializer(
                                                   EqualsValueClause(call)))));
            }

            foreach (var cppParameter in cppFunction.Parameters.Reverse())
            {
                if (delegates.ContainsKey(cppParameter.Name))
                {
                    var managedParameterName = GetManagedName(cppParameter.Name);
                    yield return(SyntaxBuilder.CallKeepAlive(IdentifierName(managedParameterName)));
                }
            }

            if (!returnTypeInfo.IsVoid)
            {
                yield return(ReturnStatement(IdentifierName("result")));
            }

            ArgumentSyntax BuildArgument(CppParameter cppParameter)
            {
                var name = delegates.TryGetValue(cppParameter.Name, out string paramName)
                    ? paramName
                    : GetManagedName(cppParameter.Name);

                return(Argument(IdentifierName(name)));
            }
        }