Exemplo n.º 1
0
        public void GenerateFunctionCall(Function function, Class @class = null, Type publicRetType = null)
        {
            CheckArgumentRange(function);

            if (function.OperatorKind == CXXOperatorKind.EqualEqual ||
                function.OperatorKind == CXXOperatorKind.ExclaimEqual)
            {
                WriteLine("bool {0}Null = ReferenceEquals({0}, nullptr);",
                          function.Parameters[0].Name);
                WriteLine("bool {0}Null = ReferenceEquals({0}, nullptr);",
                          function.Parameters[1].Name);
                WriteLine("if ({0}Null || {1}Null)",
                          function.Parameters[0].Name, function.Parameters[1].Name);
                WriteLineIndent("return {0}{1}Null && {2}Null{3};",
                                function.OperatorKind == CXXOperatorKind.EqualEqual ? string.Empty : "!(",
                                function.Parameters[0].Name, function.Parameters[1].Name,
                                function.OperatorKind == CXXOperatorKind.EqualEqual ? string.Empty : ")");
            }

            var retType = function.ReturnType;

            if (publicRetType == null)
            {
                publicRetType = retType.Type;
            }
            var needsReturn = !publicRetType.IsPrimitiveType(PrimitiveType.Void);

            const string valueMarshalName = "_this0";
            var          isValueType      = @class != null && @class.IsValueType;

            if (isValueType && !IsNativeFunctionOrStaticMethod(function))
            {
                WriteLine($"auto {valueMarshalName} = {typePrinter.PrintTag(@class)}::{@class.QualifiedOriginalName}();");

                var param = new Parameter {
                    Name = "(*this)", Namespace = function.Namespace
                };
                var ctx = new MarshalContext(Context, CurrentIndentation)
                {
                    Parameter = param
                };
                ctx.VarPrefix.Write(valueMarshalName);

                var marshal = new CLIMarshalManagedToNativePrinter(ctx);
                marshal.MarshalValueClassProperties(@class, valueMarshalName);

                if (!string.IsNullOrWhiteSpace(marshal.Context.Before))
                {
                    Write(marshal.Context.Before);
                }
            }

            var @params = GenerateFunctionParamsMarshal(function.Parameters, function);

            var returnIdentifier = Helpers.ReturnIdentifier;

            if (needsReturn)
            {
                if (retType.Type.IsReference())
                {
                    Write("auto &{0} = ", returnIdentifier);
                }
                else
                {
                    Write("auto {0} = ", returnIdentifier);
                }
            }

            if (function.OperatorKind == CXXOperatorKind.Conversion ||
                function.OperatorKind == CXXOperatorKind.ExplicitConversion)
            {
                var method   = function as Method;
                var typeName = method.ConversionType.Visit(new CppTypePrinter(Context));
                WriteLine("({0}) {1};", typeName, @params[0].Name);
            }
            else if (function.IsOperator &&
                     function.OperatorKind != CXXOperatorKind.Subscript)
            {
                var opName = function.Name.Replace("operator", "").Trim();

                switch (Operators.ClassifyOperator(function))
                {
                case CXXOperatorArity.Unary:
                    WriteLine("{0} {1};", opName, @params[0].Name);
                    break;

                case CXXOperatorArity.Binary:
                    WriteLine("{0} {1} {2};", @params[0].Name, opName, @params[1].Name);
                    break;
                }
            }
            else
            {
                if (IsNativeFunctionOrStaticMethod(function))
                {
                    Write($"::{function.QualifiedOriginalName}(");
                }
                else
                {
                    if (isValueType)
                    {
                        Write($"{valueMarshalName}.");
                    }
                    else if (IsNativeMethod(function))
                    {
                        Write($"(({typePrinter.PrintTag(@class)}::{@class.QualifiedOriginalName}*)NativePtr)->");
                    }
                    Write("{0}(", function.OriginalName);
                }

                GenerateFunctionParams(@params);
                WriteLine(");");
            }

            foreach (var paramInfo in @params)
            {
                var param = paramInfo.Param;
                if (param.Usage != ParameterUsage.Out && param.Usage != ParameterUsage.InOut)
                {
                    continue;
                }

                if (param.Type.IsPointer() && !param.Type.GetFinalPointee().IsPrimitiveType())
                {
                    param.QualifiedType = new QualifiedType(param.Type.GetFinalPointee());
                }

                var nativeVarName = paramInfo.Name;

                var ctx = new MarshalContext(Context, CurrentIndentation)
                {
                    ArgName       = nativeVarName,
                    ReturnVarName = nativeVarName,
                    ReturnType    = param.QualifiedType
                };

                var marshal = new CLIMarshalNativeToManagedPrinter(ctx);
                param.Visit(marshal);

                if (!string.IsNullOrWhiteSpace(marshal.Context.Before))
                {
                    Write(marshal.Context.Before);
                }

                WriteLine("{0} = {1};", param.Name, marshal.Context.Return);
            }

            if (isValueType && !IsNativeFunctionOrStaticMethod(function))
            {
                GenerateStructMarshaling(@class, valueMarshalName + ".");
            }

            if (needsReturn)
            {
                var retTypeName = retType.Visit(CTypePrinter).ToString();
                var isIntPtr    = retTypeName.Contains("IntPtr");

                if (retType.Type.IsPointer() && (isIntPtr || retTypeName.EndsWith("^", StringComparison.Ordinal)))
                {
                    WriteLine("if ({0} == nullptr) return {1};",
                              returnIdentifier,
                              isIntPtr ? "::System::IntPtr()" : "nullptr");
                }

                var ctx = new MarshalContext(Context, CurrentIndentation)
                {
                    ArgName       = returnIdentifier,
                    ReturnVarName = returnIdentifier,
                    ReturnType    = retType
                };

                var marshal = new CLIMarshalNativeToManagedPrinter(ctx);
                retType.Visit(marshal);

                if (!string.IsNullOrWhiteSpace(marshal.Context.Before))
                {
                    Write(marshal.Context.Before);
                }

                // Special case for indexer - needs to dereference if the internal
                // function is a pointer type and the property is not.
                if (retType.Type.IsPointer() &&
                    retType.Type.GetPointee().Equals(publicRetType) &&
                    publicRetType.IsPrimitiveType())
                {
                    WriteLine("return *({0});", marshal.Context.Return);
                }
                else if (retType.Type.IsReference() && publicRetType.IsReference())
                {
                    WriteLine("return ({0})({1});", publicRetType, marshal.Context.Return);
                }
                else
                {
                    WriteLine("return {0};", marshal.Context.Return);
                }
            }
        }
Exemplo n.º 2
0
        public void GenerateFunctionCall(Function function, Class @class = null)
        {
            var retType     = function.ReturnType;
            var needsReturn = !retType.Type.IsPrimitiveType(PrimitiveType.Void);

            const string valueMarshalName = "_this0";
            var          isValueType      = @class != null && @class.IsValueType;

            if (isValueType && !IsNativeFunctionOrStaticMethod(function))
            {
                WriteLine("auto {0} = ::{1}();", valueMarshalName, @class.QualifiedOriginalName);

                var param = new Parameter {
                    Name = "(*this)"
                };
                var ctx = new MarshalContext(Driver)
                {
                    MarshalVarPrefix = valueMarshalName,
                    Parameter        = param
                };

                var marshal = new CLIMarshalManagedToNativePrinter(ctx);
                marshal.MarshalValueClassProperties(@class, valueMarshalName);

                if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore))
                {
                    Write(marshal.Context.SupportBefore);
                }
            }

            var @params = GenerateFunctionParamsMarshal(function.Parameters, function);

            if (needsReturn)
            {
                Write("auto {0}{1} = ", (function.ReturnType.Type.IsReference())? "&": string.Empty,
                      Generator.GeneratedIdentifier("ret"));
            }

            if (function.OperatorKind == CXXOperatorKind.Conversion)
            {
                var method      = function as Method;
                var typePrinter = new CppTypePrinter(Driver.TypeDatabase);
                var typeName    = method.ConversionType.Visit(typePrinter);
                WriteLine("({0}) {1};", typeName, @params[0].Name);
            }
            else if (function.IsOperator)
            {
                var opName = function.Name.Replace("operator", "").Trim();

                switch (Operators.ClassifyOperator(function))
                {
                case CXXOperatorArity.Unary:
                    WriteLine("{0} {1};", opName, @params[0].Name);
                    break;

                case CXXOperatorArity.Binary:
                    WriteLine("{0} {1} {2};", @params[0].Name, opName,
                              @params[1].Name);
                    break;
                }
            }
            else
            {
                if (IsNativeFunctionOrStaticMethod(function))
                {
                    Write("::{0}(", function.QualifiedOriginalName);
                }
                else
                {
                    if (isValueType)
                    {
                        Write("{0}.", valueMarshalName);
                    }
                    else if (IsNativeMethod(function))
                    {
                        Write("((::{0}*)NativePtr)->", @class.QualifiedOriginalName);
                    }
                    Write("{0}(", function.OriginalName);
                }

                GenerateFunctionParams(@params);
                WriteLine(");");
            }

            foreach (var paramInfo in @params)
            {
                var param = paramInfo.Param;
                if (param.Usage != ParameterUsage.Out && param.Usage != ParameterUsage.InOut)
                {
                    continue;
                }

                var nativeVarName = paramInfo.Name;

                var ctx = new MarshalContext(Driver)
                {
                    ArgName       = nativeVarName,
                    ReturnVarName = nativeVarName,
                    ReturnType    = param.QualifiedType
                };

                var marshal = new CLIMarshalNativeToManagedPrinter(ctx);
                param.Visit(marshal);

                if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore))
                {
                    Write(marshal.Context.SupportBefore);
                }

                WriteLine("{0} = {1};", param.Name, marshal.Context.Return);
            }

            if (isValueType && !IsNativeFunctionOrStaticMethod(function))
            {
                GenerateStructMarshaling(@class, valueMarshalName + ".");
            }

            if (needsReturn)
            {
                var retTypeName = retType.Visit(TypePrinter);
                var isIntPtr    = retTypeName.Contains("IntPtr");

                if (retType.Type.IsPointer() && (isIntPtr || retTypeName.EndsWith("^")))
                {
                    WriteLine("if ({0} == nullptr) return {1};",
                              Generator.GeneratedIdentifier("ret"),
                              isIntPtr ? "System::IntPtr()" : "nullptr");
                }

                var ctx = new MarshalContext(Driver)
                {
                    ArgName       = Generator.GeneratedIdentifier("ret"),
                    ReturnVarName = Generator.GeneratedIdentifier("ret"),
                    ReturnType    = retType
                };

                var marshal = new CLIMarshalNativeToManagedPrinter(ctx);
                function.ReturnType.Visit(marshal);

                if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore))
                {
                    Write(marshal.Context.SupportBefore);
                }

                WriteLine("return {0};", marshal.Context.Return);
            }
        }