예제 #1
0
        private void WriteMethodMarshal(ManagedMethod method, int numParameters)
        {
            var    nativeMethod = method.Native;
            string methodName   = nativeMethod.IsConstructor ?
                                  $"{nativeMethod.Parent.FullyQualifiedName}" : $"{nativeMethod.Name}";

            var currentParams = method.Parameters.Take(numParameters);
            var paramStrings  = currentParams.Select(p =>
            {
                string marshal = BulletParser.GetTypeMarshalCppCli(p);
                if (!string.IsNullOrEmpty(marshal))
                {
                    return(marshal);
                }

                var paramType = p.Native.Type;
                if (paramType.IsBasic)
                {
                    return(p.Name);
                }

                string paramString = "";
                switch (paramType.Kind)
                {
                case TypeKind.Pointer:
                case TypeKind.LValueReference:
                    if (paramType.Kind == TypeKind.LValueReference)
                    {
                        // Dereference
                        paramString = "*";
                    }

                    if (paramType.Referenced.Target?.BaseClass != null)
                    {
                        // Cast native pointer from base class
                        paramString += $"({paramType.Referenced.FullName}*)";
                    }
                    break;
                }

                paramString += p.Name;
                if (paramType.Kind == TypeKind.Pointer && paramType.Referenced.Kind == TypeKind.Void)
                {
                    paramString += ".ToPointer()";
                }
                else
                {
                    paramString += "->_native";
                }
                return(paramString);
            });

            Write($"{methodName}(");
            string parameters = ListToLines(paramStrings, WriteTo.Source, 1);

            Write($"{parameters})");
        }
예제 #2
0
        static void Main(string[] args)
        {
            // If true, outputs C++/CLI wrapper,
            // if false, outputs C wrapper with C# code.
            bool cppCliMode = false;

            var project = WrapperProject.FromFile("bullet3.xml");

            if (!project.VerifyFiles())
            {
                Console.ReadKey();
                return;
            }

            project.ReadCpp();
            var parser = new BulletParser(project);

            parser.Parse();
            Console.WriteLine("Parsing complete");

            CWriter cWriter = new CWriter(parser);

            //project.CProjectPath = "c_temp";
            cWriter.Output();

            DotNetWriter dotNetWriter;

            if (cppCliMode)
            {
                dotNetWriter = new CppCliWriter(parser);
            }
            else
            {
                dotNetWriter = new PInvokeWriter(parser);

                var extensionsWriter = new ExtensionsWriter(parser);
                extensionsWriter.Output();
            }
            dotNetWriter.Output();

            OutputSolution(TargetVS.VS2008, parser);
            OutputSolution(TargetVS.VS2010, parser);
            OutputSolution(TargetVS.VS2012, parser);
            OutputSolution(TargetVS.VS2013, parser);
            OutputSolution(TargetVS.VS2015, parser);
            //project.Save();

            CMakeWriter cmake = new CMakeWriter(parser);

            cmake.Output();

            Console.Write("Press any key to continue...");
            Console.ReadKey();
        }
예제 #3
0
        static void Main(string[] args)
        {
            // If true, outputs C++/CLI wrapper,
            // if false, outputs C wrapper with C# code.
            bool cppCliMode = false;

            //var subset = new AssemblySubset();
            //subset.LoadAssembly("..\\..\\..\\bulletsharp\\demos\\Generic\\bin\\Release\\BasicDemo.exe", "BulletSharp");
            //subset.LoadAssembly("..\\..\\..\\bulletsharp\\demos\\Generic\\bin\\Release\\DemoFramework.dll", "BulletSharp");

            string sourceFolder = "D:\\src\\bullet3\\src\\";

            //sourceFolder = "..\\..\\..\\bullet\\src\\";

            if (!Directory.Exists(sourceFolder))
            {
                Console.WriteLine("Source folder \"" + sourceFolder + "\" not found");
                Console.Write("Press any key to continue...");
                Console.ReadKey();
                return;
            }

            var reader          = new CppReader(sourceFolder);
            var parser          = new BulletParser(reader.ClassDefinitions, reader.HeaderDefinitions);
            var externalHeaders = parser.ExternalHeaders.Values;

            if (cppCliMode)
            {
                var writer = new CppCliWriter(externalHeaders, NamespaceName);
                writer.Output();
            }
            else
            {
                var writer = new PInvokeWriter(externalHeaders, NamespaceName);
                writer.Output();

                var extensionWriter = new ExtensionsWriter(externalHeaders, NamespaceName);
                extensionWriter.Output();
            }


            OutputSolution(TargetVS.VS2008, externalHeaders);
            OutputSolution(TargetVS.VS2010, externalHeaders);
            OutputSolution(TargetVS.VS2012, externalHeaders);
            OutputSolution(TargetVS.VS2013, externalHeaders);

            CMakeWriter cmake = new CMakeWriter(parser.ExternalHeaders, NamespaceName);

            cmake.Output();

            Console.Write("Press any key to continue...");
            Console.ReadKey();
        }
예제 #4
0
        static void Main(string[] args)
        {
            // If true, outputs C++/CLI wrapper,
            // if false, outputs C wrapper with C# code.
            bool cppCliMode = false;

            var project = WrapperProject.FromFile("bullet3.xml");
            if (!project.VerifyFiles())
            {
                Console.ReadKey();
                return;
            }

            project.ReadCpp();
            var parser = new BulletParser(project);
            parser.Parse();
            Console.WriteLine("Parsing complete");

            CWriter cWriter = new CWriter(parser);
            //project.CProjectPath = "c_temp";
            cWriter.Output();

            DotNetWriter dotNetWriter;
            if (cppCliMode)
            {
                dotNetWriter = new CppCliWriter(parser);
            }
            else
            {
                dotNetWriter = new PInvokeWriter(parser);

                var extensionsWriter = new ExtensionsWriter(parser);
                extensionsWriter.Output();
            }
            dotNetWriter.Output();

            OutputSolution(TargetVS.VS2008, parser);
            OutputSolution(TargetVS.VS2010, parser);
            OutputSolution(TargetVS.VS2012, parser);
            OutputSolution(TargetVS.VS2013, parser);
            OutputSolution(TargetVS.VS2015, parser);
            //project.Save();

            CMakeWriter cmake = new CMakeWriter(parser);
            cmake.Output();

            Console.Write("Press any key to continue...");
            Console.ReadKey();
        }
예제 #5
0
        static void Main(string[] args)
        {
            // If true, outputs C++/CLI wrapper,
            // if false, outputs C wrapper with C# code.
            bool cppCliMode = false;

            var project = WrapperProject.FromFile("bullet3.xml");

            if (!project.VerifyFiles())
            {
                Console.ReadKey();
                return;
            }

            var reader = new CppReader(project);
            var parser = new BulletParser(project);

            parser.Parse();
            Console.WriteLine("Parsing complete");

            WrapperWriter writer;

            if (cppCliMode)
            {
                writer = new CppCliWriter(project.HeaderDefinitions.Values, project.NamespaceName);
            }
            else
            {
                writer = new PInvokeWriter(project);

                var extensionWriter = new ExtensionsWriter(project.HeaderDefinitions.Values, project.NamespaceName);
                extensionWriter.Output();
            }
            writer.Output();

            OutputSolution(TargetVS.VS2008, project);
            OutputSolution(TargetVS.VS2010, project);
            OutputSolution(TargetVS.VS2012, project);
            OutputSolution(TargetVS.VS2013, project);
            OutputSolution(TargetVS.VS2015, project);
            //project.Save();

            CMakeWriter cmake = new CMakeWriter(project.HeaderDefinitions, project.NamespaceName);

            cmake.Output();

            Console.Write("Press any key to continue...");
            Console.ReadKey();
        }
예제 #6
0
        static void Main(string[] args)
        {
            // If true, outputs C++/CLI wrapper,
            // if false, outputs C wrapper with C# code.
            bool cppCliMode = false;

            //var subset = new AssemblySubset();
            //subset.LoadAssembly("..\\..\\..\\bulletsharp\\demos\\Generic\\bin\\Release\\BasicDemo.exe", "BulletSharp");
            //subset.LoadAssembly("..\\..\\..\\bulletsharp\\demos\\Generic\\bin\\Release\\DemoFramework.dll", "BulletSharp");

            string sourceFolder = "D:\\src\\bullet3\\src\\";
            //sourceFolder = "..\\..\\..\\bullet\\src\\";

            if (!Directory.Exists(sourceFolder))
            {
                Console.WriteLine("Source folder \"" + sourceFolder + "\" not found");
                Console.Write("Press any key to continue...");
                Console.ReadKey();
                return;
            }

            var reader = new CppReader(sourceFolder);
            var parser = new BulletParser(reader.ClassDefinitions, reader.HeaderDefinitions);
            var externalHeaders = parser.ExternalHeaders.Values;
            if (cppCliMode)
            {
                var writer = new CppCliWriter(externalHeaders, NamespaceName);
                writer.Output();
            }
            else
            {
                var writer = new PInvokeWriter(externalHeaders, NamespaceName);
                writer.Output();

                var extensionWriter = new ExtensionsWriter(externalHeaders, NamespaceName);
                extensionWriter.Output();
            }

            OutputSolution(TargetVS.VS2008, externalHeaders);
            OutputSolution(TargetVS.VS2010, externalHeaders);
            OutputSolution(TargetVS.VS2012, externalHeaders);
            OutputSolution(TargetVS.VS2013, externalHeaders);

            CMakeWriter cmake = new CMakeWriter(parser.ExternalHeaders, NamespaceName);
            cmake.Output();

            Console.Write("Press any key to continue...");
            Console.ReadKey();
        }
예제 #7
0
        static void Main(string[] args)
        {
            // If true, outputs C++/CLI wrapper,
            // if false, outputs C wrapper with C# code.
            bool cppCliMode = false;

            var project = WrapperProject.FromFile("bullet3.xml");
            if (!project.VerifyFiles())
            {
                Console.ReadKey();
                return;
            }

            var reader = new CppReader(project);
            var parser = new BulletParser(project);
            parser.Parse();
            Console.WriteLine("Parsing complete");

            WrapperWriter writer;
            if (cppCliMode)
            {
                writer = new CppCliWriter(project);
            }
            else
            {
                writer = new PInvokeWriter(project);

                var extensionWriter = new ExtensionsWriter(project.HeaderDefinitions.Values, project.NamespaceName);
                extensionWriter.Output();
            }
            writer.Output();

            OutputSolution(TargetVS.VS2008, project);
            OutputSolution(TargetVS.VS2010, project);
            OutputSolution(TargetVS.VS2012, project);
            OutputSolution(TargetVS.VS2013, project);
            OutputSolution(TargetVS.VS2015, project);
            //project.Save();

            CMakeWriter cmake = new CMakeWriter(project);
            cmake.Output();

            Console.Write("Press any key to continue...");
            Console.ReadKey();
        }
예제 #8
0
        void WriteProperty(PropertyDefinition prop, int level)
        {
            var getterNative = prop.Getter.Native;
            var setterNative = prop.Setter?.Native;

            EnsureWhiteSpace();

            Write(level + 1, $"public ");
            if (getterNative.IsStatic)
            {
                Write("static ");
            }
            WriteLine($"{GetTypeNameCS(prop.Type)} {prop.Name}");
            WriteLine(level + 1, "{");

            if (prop.Parent.CachedProperties.ContainsKey(prop.Name))
            {
                var cachedProperty = prop.Parent.CachedProperties[prop.Name];
                WriteLine(level + 2, $"get {{ return {cachedProperty.CacheFieldName}; }}");

                if (setterNative != null)
                {
                    WriteLine(level + 2, "set");
                    WriteLine(level + 2, "{");
                    Write(level + 3, $"{GetFullNameC(prop.Parent.Native)}_{setterNative.Name}(");
                    if (!setterNative.IsStatic)
                    {
                        Write("_native, ");
                    }
                    WriteLine($"{GetTypeSetterCSMarshal(prop.Type)});");
                    WriteLine(level + 3, $"{cachedProperty.CacheFieldName} = value;");
                    WriteLine(level + 2, "}");
                }
            }
            else
            {
                var type = prop.Type;
                if ((type.Target != null && type.Target.MarshalAsStruct) ||
                    (type.Kind == TypeKind.LValueReference && type.Referenced.Target != null && type.Referenced.Target.MarshalAsStruct))
                {
                    WriteLine(level + 2, "get");
                    WriteLine(level + 2, "{");
                    WriteLine(level + 3, $"{GetTypeNameCS(type)} value;");
                    Write(level + 3, $"{GetFullNameC(prop.Parent.Native)}_{getterNative.Name}(");
                    if (!getterNative.IsStatic)
                    {
                        Write("_native, ");
                    }
                    WriteLine("out value);");
                    WriteLine(level + 3, "return value;");
                    WriteLine(level + 2, "}");
                }
                else
                {
                    string objPtr = getterNative.IsStatic ? "" : "_native";
                    WriteLine(level + 2, string.Format("get {{ return {0}{1}_{2}({3}){4}; }}",
                                                       BulletParser.GetTypeMarshalConstructorStartCS(getterNative),
                                                       GetFullNameC(prop.Parent.Native), getterNative.Name,
                                                       objPtr,
                                                       BulletParser.GetTypeMarshalConstructorEndCS(getterNative)));
                }

                if (setterNative != null)
                {
                    string marshal = GetTypeSetterCSMarshal(prop.Type);
                    Write(level + 2,
                          $"set {{ {GetFullNameC(prop.Parent.Native)}_{setterNative.Name}(");
                    if (!setterNative.IsStatic)
                    {
                        Write("_native, ");
                    }
                    WriteLine($"{marshal}); }}");
                }
            }

            WriteLine(level + 1, "}");

            hasCSWhiteSpace = false;
        }
예제 #9
0
        void WriteMethodDefinition(ManagedMethod method, int numParameters, int overloadIndex, int level,
                                   ManagedParameter outValueParameter)
        {
            var nativeMethod = method.Native;

            if (nativeMethod.IsConstructor)
            {
                if (method.Parent.BaseClass == null)
                {
                    Write("_native = ");
                }
                Write($"{GetFullNameC(method.Parent.Native)}_new");
            }
            else
            {
                if (!nativeMethod.IsVoid)
                {
                    if (outValueParameter != null)
                    {
                        // Temporary variable
                        WriteLine(string.Format("{0} {1};",
                                                DotNetParser.GetManaged(outValueParameter.Native.Type.Referenced.Target).Name,
                                                outValueParameter.Name));
                        WriteTabs(level + 2);
                    }
                    else
                    {
                        Write($"return {BulletParser.GetTypeMarshalConstructorStartCS(nativeMethod)}");
                    }
                }

                Write($"{GetFullNameC(method.Parent.Native)}_{method.Native.Name}");
            }

            if (overloadIndex != 0)
            {
                Write((overloadIndex + 1).ToString());
            }

            Write('(');

            var parameters = method.Parameters.Take(numParameters)
                             .Select(p => GetParameterMarshal(p));

            if (outValueParameter != null)
            {
                parameters = parameters.Concat(new[] { $"out {outValueParameter.Name }" });
            }

            // The first parameter is the instance pointer (if not constructor or static method)
            if (!nativeMethod.IsConstructor && !nativeMethod.IsStatic)
            {
                parameters = new[] { "_native" }.Concat(parameters);
            }

            Write(ListToLines(parameters, WriteTo.CS, level + 2));

            if (nativeMethod.IsConstructor && method.Parent.BaseClass != null)
            {
                Write(")");
                if (method.Parent.BaseClass.Native.HasPreventDelete)
                {
                    Write(", false");
                }
                WriteLine(")");
                WriteLine(level + 1, "{");
            }
            else
            {
                if (!nativeMethod.IsConstructor && !nativeMethod.IsVoid)
                {
                    Write(BulletParser.GetTypeMarshalConstructorEndCS(nativeMethod));
                }
                WriteLine(");");
            }

            // Cache property values
            if (nativeMethod.IsConstructor)
            {
                var methodParent = method.Parent;
                while (methodParent != null)
                {
                    foreach (var cachedProperty in methodParent.CachedProperties.OrderBy(p => p.Key))
                    {
                        foreach (var param in method.Parameters)
                        {
                            if (param.Name.ToLower().Equals(cachedProperty.Key.ToLower()) &&
                                GetName(param.Native.Type).Equals(GetName(cachedProperty.Value.Property.Type)))
                            {
                                WriteLine(level + 2,
                                          $"{cachedProperty.Value.CacheFieldName} = {param.Name};");
                            }
                        }
                    }
                    methodParent = methodParent.BaseClass;
                }
            }

            // Return temporary variable
            if (outValueParameter != null)
            {
                WriteLine(level + 2, $"return {outValueParameter.Name};");
            }
        }
예제 #10
0
        void OutputClass(ClassDefinition c, int level)
        {
            EnsureHeaderWhiteSpace();
            EnsureSourceWhiteSpace();

            // Write access modifier
            WriteTabs(level);
            if (level == 1)
            {
                HeaderWrite("public ");
            }

            // Write class definition
            HeaderWrite("ref class ");
            HeaderWrite(c.ManagedName);
            if (c.IsAbstract)
            {
                HeaderWrite(" abstract");
            }
            if (c.BaseClass != null)
            {
                HeaderWrite(" : ");
                HeaderWriteLine(c.BaseClass.ManagedName);
            }
            else
            {
                if (c.IsTrackingDisposable)
                {
                    HeaderWriteLine(" : ITrackingDisposable");
                }
                else
                {
                    // In C++/CLI, IDisposable is inherited automatically if the destructor and finalizer are defined
                    //HeaderWriteLine(" : IDisposable");
                    if (c.IsStaticClass)
                    {
                        HeaderWrite(" sealed");
                    }
                    HeaderWriteLine();
                }
            }

            WriteTabs(level);
            HeaderWriteLine("{");
            //hasHeaderWhiteSpace = false;

            // Default access for ref class
            var currentAccess = RefAccessSpecifier.Private;

            // Write child classes
            if (c.Classes.Count != 0)
            {
                OutputClasses(c.Classes, ref currentAccess, level);
                currentAccess = RefAccessSpecifier.Public;
                SourceWriteLine();
            }

            // Classes without instances
            if (c.IsStaticClass)
            {
                EnsureAccess(level, ref currentAccess, RefAccessSpecifier.Private);
                WriteTabs(level + 1);
                HeaderWriteLine(string.Format("{0}() {{}}", c.ManagedName));
            }

            // Downcast native pointer if any methods in a derived class use it
            if (c.BaseClass != null && c.Methods.Any(m => !m.IsConstructor && !m.IsStatic))
            {
                EnsureSourceWhiteSpace();
                SourceWriteLine(string.Format("#define Native static_cast<{0}*>(_native)", c.FullName));
                hasSourceWhiteSpace = false;
            }

            // Write the unmanaged pointer to the base class
            if (c.BaseClass == null && !c.IsStaticClass)
            {
                if (c.Classes.Count != 0)
                {
                    HeaderWriteLine();
                }
                if (c.IsTrackingDisposable)
                {
                    EnsureAccess(level, ref currentAccess, RefAccessSpecifier.Public);
                    WriteTabs(level + 1);
                    HeaderWriteLine("virtual event EventHandler^ OnDisposing;");
                    WriteTabs(level + 1);
                    HeaderWriteLine("virtual event EventHandler^ OnDisposed;");
                    hasHeaderWhiteSpace = false;
                }
                EnsureAccess(level, ref currentAccess, RefAccessSpecifier.Internal);

                WriteTabs(level + 1);
                HeaderWrite(c.FullName);
                HeaderWriteLine("* _native;");
                hasHeaderWhiteSpace = false;
            }

            EnsureHeaderWhiteSpace();
            EnsureSourceWhiteSpace();

            // Private fields
            // _isDisposed flag
            if (c.IsTrackingDisposable)
            {
                EnsureAccess(level, ref currentAccess, RefAccessSpecifier.Private);
                WriteTabs(level + 1);
                HeaderWriteLine("bool _isDisposed;");
                hasHeaderWhiteSpace = false;
            }
            // _preventDelete flag
            if (c.HasPreventDelete)
            {
                EnsureAccess(level, ref currentAccess, RefAccessSpecifier.Private);
                WriteTabs(level + 1);
                HeaderWriteLine("bool _preventDelete;");
                hasHeaderWhiteSpace = false;
            }

            // Write unmanaged constructor
            // TODO: Write constructor from unmanaged pointer only if the class is ever instantiated in this way.
            if (!c.NoInternalConstructor && !c.IsStaticClass)
            {
                EnsureAccess(level, ref currentAccess, RefAccessSpecifier.Internal);

                WriteTabs(level + 1);
                SourceWrite(c.FullNameManaged);
                SourceWrite("::");
                Write(c.ManagedName);
                Write('(');
                Write(c.FullName);
                Write("* native)");
                HeaderWriteLine(';');
                SourceWriteLine();
                if (c.BaseClass != null)
                {
                    WriteTabs(1, true);
                    SourceWrite(": ");
                    SourceWrite(c.BaseClass.ManagedName);
                    SourceWriteLine("(native)");
                }
                SourceWriteLine('{');
                if (c.BaseClass == null)
                {
                    WriteTabs(1, true);
                    SourceWriteLine("_native = native;");
                }
                SourceWriteLine('}');
                hasHeaderWhiteSpace = false;
                hasSourceWhiteSpace = false;
            }

            // Write destructor & finalizer
            if (c.BaseClass == null && !c.IsStaticClass)
            {
                EnsureAccess(level, ref currentAccess, RefAccessSpecifier.Public);
                WriteTabs(level + 1);
                HeaderWriteLine(string.Format("!{0}();", c.ManagedName));
                EnsureAccess(level, ref currentAccess, RefAccessSpecifier.Protected);
                WriteTabs(level + 1);
                HeaderWriteLine(string.Format("~{0}();", c.ManagedName));
                hasHeaderWhiteSpace = false;

                EnsureSourceWhiteSpace();
                SourceWriteLine(string.Format("{0}::~{1}()", c.FullNameManaged, c.ManagedName));
                SourceWriteLine('{');
                SourceWriteLine(string.Format("\tthis->!{0}();", c.ManagedName));
                SourceWriteLine('}');
                SourceWriteLine();

                SourceWriteLine(string.Format("{0}::!{1}()", c.FullNameManaged, c.ManagedName));
                SourceWriteLine('{');
                if (c.IsTrackingDisposable)
                {
                    SourceWriteLine("\tif (this->IsDisposed)");
                    SourceWriteLine("\t\treturn;");
                    SourceWriteLine();
                    SourceWriteLine("\tOnDisposing(this, nullptr);");
                    SourceWriteLine();
                }
                if (c.HasPreventDelete)
                {
                    SourceWriteLine("\tif (!_preventDelete)");
                    SourceWriteLine("\t{");
                    SourceWriteLine("\t\tdelete _native;");
                    SourceWriteLine("\t}");
                }
                else
                {
                    SourceWriteLine("\tdelete _native;");
                }
                if (c.IsTrackingDisposable)
                {
                    SourceWriteLine("\t_isDisposed = true;");
                    SourceWriteLine();
                    SourceWriteLine("\tOnDisposed(this, nullptr);");
                }
                else
                {
                    SourceWriteLine("\t_native = NULL;");
                }
                SourceWriteLine('}');
                hasSourceWhiteSpace = false;
            }

            // Write constructors
            int constructorCount = 0;

            foreach (MethodDefinition method in c.Methods.Where(m => m.IsConstructor))
            {
                if (!c.HidePublicConstructors)
                {
                    EnsureAccess(level, ref currentAccess, RefAccessSpecifier.Public);
                    OutputMethod(method, level);
                }
                constructorCount++;
            }

            // Write default constructor
            if (constructorCount == 0 && !c.IsAbstract && !c.HidePublicConstructors && !c.IsStaticClass)
            {
                EnsureAccess(level, ref currentAccess, RefAccessSpecifier.Public);

                MethodDefinition constructor = new MethodDefinition(c.Name, c, 0);
                constructor.IsConstructor = true;
                OutputMethod(constructor, level);
                constructorCount++;
            }

            // Write methods
            if (c.Methods.Count - constructorCount != 0)
            {
                EnsureHeaderWhiteSpace();

                foreach (MethodDefinition method in c.Methods)
                {
                    if (!method.IsConstructor && method.Property == null)
                    {
                        EnsureAccess(level, ref currentAccess, RefAccessSpecifier.Public);
                        OutputMethod(method, level);
                    }
                }
            }

            // Write properties (includes unmanaged fields and getters/setters)
            foreach (PropertyDefinition prop in c.Properties)
            {
                string typeConditional = GetTypeConditional(prop.Type, c.Header);
                if (typeConditional != null)
                {
                    Write("#ifndef ");
                    WriteLine(typeConditional);
                    hasSourceWhiteSpace = true;
                }
                else
                {
                    EnsureHeaderWhiteSpace();
                }

                EnsureAccess(level, ref currentAccess, RefAccessSpecifier.Public);

                string typeRefName = BulletParser.GetTypeRefName(prop.Type);

                WriteTabs(level + 1);
                HeaderWrite("property ");
                HeaderWrite(typeRefName);
                HeaderWrite(" ");
                HeaderWriteLine(prop.Name);
                WriteTabs(level + 1);
                HeaderWriteLine("{");

                // Getter/Setter
                OutputMethod(prop.Getter, level + 1);
                if (prop.Setter != null)
                {
                    OutputMethod(prop.Setter, level + 1);
                }

                WriteTabs(level + 1);
                HeaderWriteLine("}");

                if (typeConditional != null)
                {
                    WriteLine("#endif");
                    hasSourceWhiteSpace = false;
                }

                hasHeaderWhiteSpace = false;
            }

            WriteTabs(level);
            HeaderWriteLine("};");
            hasHeaderWhiteSpace = false;
        }
예제 #11
0
        void OutputMethod(MethodDefinition method, int level, int numOptionalParams = 0)
        {
            var parentClass = method.Parent;

            // No whitespace between get/set methods
            if (!(method.Property != null &&
                  method.Equals(method.Property.Setter)))
            {
                EnsureSourceWhiteSpace();
                hasHeaderWhiteSpace = false;
            }

            // #ifndef DISABLE_FEATURE
            bool hasConditional = false;

            if (method.Property == null)
            {
                foreach (var param in method.Parameters)
                {
                    string typeConditional = GetTypeConditional(param.Type, parentClass.Header);
                    if (typeConditional != null)
                    {
                        Write("#ifndef ");
                        WriteLine(typeConditional);
                        hasSourceWhiteSpace = true;
                        hasConditional      = true;
                    }
                }
            }

            WriteTabs(level + 1);

            // "static"
            if (method.IsStatic)
            {
                HeaderWrite("static ");
            }

            // Definition: return type
            if (!method.IsConstructor)
            {
                var returnType = method.ReturnType;

                if (method.Property != null)
                {
                    if (method.Equals(method.Property.Getter))
                    {
                        // If property name matches type name, resolve ambiguity
                        if (method.Property.Name.Equals(method.Property.Type.ManagedName))
                        {
                            HeaderWrite(NamespaceName + "::");
                        }

                        // Getter with parameter for return value
                        if (method.Parameters.Length == 1)
                        {
                            returnType = method.Parameters[0].Type;
                        }
                    }
                }

                Write(BulletParser.GetTypeRefName(returnType));
                Write(' ');
            }

            // Definition: name
            SourceWrite(parentClass.FullNameManaged);
            SourceWrite("::");
            if (method.IsConstructor)
            {
                Write(parentClass.ManagedName);
            }
            else
            {
                if (method.Property != null)
                {
                    SourceWrite(method.Property.Name);
                    SourceWrite("::");
                    if (method.Property.Getter.Equals(method))
                    {
                        Write("get");
                    }
                    else
                    {
                        Write("set");
                    }
                }
                else
                {
                    Write(method.ManagedName);
                }
            }
            Write('(');

            // Definition: parameters
            int numParameters = method.Parameters.Length - numOptionalParams;

            // Getters with parameter for return value
            if (numParameters == 1 && method.Property != null && method.Equals(method.Property.Getter))
            {
                numParameters = 0;
            }
            bool hasOptionalParam = false;

            for (int i = 0; i < numParameters; i++)
            {
                var param = method.Parameters[i];
                Write(BulletParser.GetTypeRefName(param.Type));
                Write(' ');
                Write(param.ManagedName);

                if (param.IsOptional)
                {
                    hasOptionalParam = true;
                }

                if (i != numParameters - 1)
                {
                    if (_headerLineLength >= LineBreakWidth)
                    {
                        HeaderWriteLine(",");
                        WriteTabs(level + 2);
                    }
                    else
                    {
                        HeaderWrite(", ");
                    }

                    if (_sourceLineLength >= LineBreakWidth)
                    {
                        SourceWriteLine(",");
                        WriteTabs(1, true);
                    }
                    else
                    {
                        SourceWrite(", ");
                    }
                }
            }
            HeaderWriteLine(");");
            SourceWriteLine(')');


            // Constructor chaining
            bool doConstructorChaining = false;

            if (method.IsConstructor && parentClass.BaseClass != null)
            {
                // If there is no need for marshalling code, we can chain constructors
                doConstructorChaining = true;
                foreach (var param in method.Parameters)
                {
                    if (BulletParser.TypeRequiresMarshal(param.Type))
                    {
                        doConstructorChaining = false;
                        break;
                    }
                }

                WriteTabs(1, true);
                SourceWrite(": ");
                SourceWrite(parentClass.BaseClass.ManagedName);
                SourceWrite('(');

                if (doConstructorChaining)
                {
                    SourceWrite("new ");
                    OutputMethodMarshal(method, numParameters);
                    if (parentClass.BaseClass.Target.HasPreventDelete)
                    {
                        SourceWrite(", false");
                    }
                }
                else
                {
                    SourceWrite('0');
                }

                SourceWriteLine(')');
            }

            // Method definition
            SourceWriteLine('{');

            if (!doConstructorChaining)
            {
                // Type marshalling prologue
                bool needTypeMarshalEpilogue = false;
                if (method.Field == null)
                {
                    for (int i = 0; i < numParameters; i++)
                    {
                        var    param    = method.Parameters[i];
                        string prologue = BulletParser.GetTypeMarshalPrologueCppCli(param);
                        if (!string.IsNullOrEmpty(prologue))
                        {
                            WriteTabs(1, true);
                            SourceWriteLine(prologue);
                        }

                        // Do we need a type marshalling epilogue?
                        if (!needTypeMarshalEpilogue)
                        {
                            string epilogue = BulletParser.GetTypeMarshalEpilogueCppCli(param);
                            if (!string.IsNullOrEmpty(epilogue))
                            {
                                needTypeMarshalEpilogue = true;
                            }
                        }
                    }
                }

                WriteTabs(1, true);
                if (method.IsConstructor)
                {
                    SourceWrite("_native = new ");
                }
                else
                {
                    if (!method.IsVoid)
                    {
                        //if (method.ReturnType.IsBasic || method.ReturnType.Referenced != null)
                        if (needTypeMarshalEpilogue)
                        {
                            // Return after epilogue (cleanup)
                            SourceWrite(BulletParser.GetTypeRefName(method.ReturnType));
                            SourceWrite(" ret = ");
                        }
                        else
                        {
                            // Return immediately
                            SourceWrite("return ");
                        }
                        SourceWrite(BulletParser.GetTypeMarshalConstructorStart(method));
                    }
                    else
                    {
                        if (method.Property != null && method.Equals(method.Property.Getter))
                        {
                            SourceWrite(BulletParser.GetTypeMarshalConstructorStart(method));
                        }
                    }
                }

                // Native is defined as static_cast<className*>(_native)
                string nativePointer = (parentClass.BaseClass != null) ? "Native" : "_native";

                if (method.Field != null)
                {
                    if (method.Equals(method.Property.Getter))
                    {
                        SourceWrite(nativePointer);
                        SourceWrite("->");
                        SourceWrite(method.Field.Name);
                    }

                    var setter = method.Property.Setter;
                    if (setter != null && method.Equals(setter))
                    {
                        var param    = method.Parameters[0];
                        var fieldSet = BulletParser.GetTypeMarshalFieldSetCppCli(method.Field, param, nativePointer);
                        if (!string.IsNullOrEmpty(fieldSet))
                        {
                            SourceWrite(fieldSet);
                        }
                        else
                        {
                            SourceWrite(string.Format("{0}->{1} = ", nativePointer, method.Field.Name));
                            if (param.Type.IsPointer || param.Type.IsReference)
                            {
                                if (param.Type.IsReference)
                                {
                                    // Dereference
                                    SourceWrite('*');
                                }

                                if (param.Type.Referenced.Target != null &&
                                    param.Type.Referenced.Target.BaseClass != null)
                                {
                                    // Cast native pointer from base class
                                    SourceWrite(string.Format("({0}*)", param.Type.Referenced.FullName));
                                }
                            }
                            SourceWrite(param.ManagedName);
                            if (!param.Type.IsBasic)
                            {
                                SourceWrite("->_native");
                            }
                        }
                    }
                }
                else
                {
                    if (!method.IsConstructor)
                    {
                        if (method.IsStatic)
                        {
                            SourceWrite(parentClass.FullName);
                            SourceWrite("::");
                        }
                        else
                        {
                            SourceWrite(nativePointer);
                            SourceWrite("->");
                        }
                    }
                    OutputMethodMarshal(method, numParameters);
                }
                if (!method.IsConstructor && !method.IsVoid)
                {
                    SourceWrite(BulletParser.GetTypeMarshalConstructorEnd(method));
                }
                SourceWriteLine(';');

                // Write type marshalling epilogue
                if (needTypeMarshalEpilogue)
                {
                    for (int i = 0; i < numParameters; i++)
                    {
                        var    param    = method.Parameters[i];
                        string epilogue = BulletParser.GetTypeMarshalEpilogueCppCli(param);
                        if (!string.IsNullOrEmpty(epilogue))
                        {
                            WriteTabs(1, true);
                            SourceWriteLine(epilogue);
                        }
                    }
                    if (!method.IsVoid)
                    {
                        WriteTabs(1, true);
                        SourceWriteLine("return ret;");
                    }
                }
            }
            SourceWriteLine('}');
            hasSourceWhiteSpace = false;

            // #endif // DISABLE_FEATURE
            if (hasConditional)
            {
                foreach (var param in method.Parameters)
                {
                    string typeConditional = GetTypeConditional(param.Type, method.Parent.Header);
                    if (typeConditional != null)
                    {
                        WriteLine("#endif");
                        hasHeaderWhiteSpace = true;
                    }
                }
            }

            // If there are optional parameters, then output all possible combinations of calls
            if (hasOptionalParam)
            {
                OutputMethod(method, level, numOptionalParams + 1);
            }
        }
예제 #12
0
        void OutputMethodMarshal(MethodDefinition method, int numParameters)
        {
            if (method.IsConstructor)
            {
                SourceWrite(method.Parent.FullName);
            }
            else
            {
                SourceWrite(method.Name);
            }
            SourceWrite('(');
            for (int i = 0; i < numParameters; i++)
            {
                var    param   = method.Parameters[i];
                string marshal = BulletParser.GetTypeMarshalCppCli(param);
                if (!string.IsNullOrEmpty(marshal))
                {
                    SourceWrite(marshal);
                }
                else if (param.Type.IsBasic)
                {
                    SourceWrite(param.ManagedName);
                }
                else
                {
                    if (param.Type.IsPointer || param.Type.IsReference)
                    {
                        if (param.Type.IsReference)
                        {
                            // Dereference
                            SourceWrite('*');
                        }

                        if (param.Type.Referenced.Target != null &&
                            param.Type.Referenced.Target.BaseClass != null)
                        {
                            // Cast native pointer from base class
                            SourceWrite(string.Format("({0}*)", param.Type.Referenced.FullName));
                        }
                    }
                    SourceWrite(param.ManagedName);
                    if (param.Type.IsPointer && param.Type.ManagedName.Equals("void"))
                    {
                        SourceWrite(".ToPointer()");
                    }
                    else
                    {
                        SourceWrite("->_native");
                    }
                }

                // Any more parameters?
                if (i != numParameters - 1)
                {
                    if (_sourceLineLength >= LineBreakWidth)
                    {
                        SourceWriteLine(",");
                        WriteTabs(2, true);
                    }
                    else
                    {
                        SourceWrite(", ");
                    }
                }
            }
            SourceWrite(')');
        }
예제 #13
0
        void WriteMethodDefinition(ManagedMethod method, int numParameters)
        {
            var nativeMethod = method.Native;
            var parentClass  = method.Parent.Native;

            // Type marshalling prologue
            bool needTypeMarshalEpilogue = false;

            if (nativeMethod.Field == null)
            {
                foreach (var param in method.Parameters)
                {
                    string prologue = BulletParser.GetTypeMarshalPrologueCppCli(param);
                    if (!string.IsNullOrEmpty(prologue))
                    {
                        WriteLine(1, prologue);
                    }

                    // Do we need a type marshalling epilogue?
                    if (!needTypeMarshalEpilogue)
                    {
                        string epilogue = BulletParser.GetTypeMarshalEpilogueCppCli(param);
                        if (!string.IsNullOrEmpty(epilogue))
                        {
                            needTypeMarshalEpilogue = true;
                        }
                    }
                }
            }

            WriteTabs(1);
            if (nativeMethod.IsConstructor)
            {
                Write("_native = new ");
            }
            else if (!nativeMethod.IsVoid)
            {
                //if (method.ReturnType.IsBasic || method.ReturnType.Referenced != null)
                if (needTypeMarshalEpilogue)
                {
                    // Return after epilogue (cleanup)
                    Write($"{GetTypeName(nativeMethod.ReturnType)} ret = ");
                }
                else
                {
                    // Return immediately
                    Write("return ");
                }
                Write(BulletParser.GetTypeMarshalConstructorStart(nativeMethod));
            }
            else if (method.Property != null && method.Equals(method.Property.Getter))
            {
                Write(BulletParser.GetTypeMarshalConstructorStart(nativeMethod));
            }

            // Native is defined as static_cast<className*>(_native)
            string nativePointer = (parentClass.BaseClass != null) ? "Native" : "_native";

            if (nativeMethod.Field != null)
            {
                var property = method.Property;
                if (method.Equals(property.Getter))
                {
                    CachedProperty cachedProperty;
                    if (method.Parent.CachedProperties.TryGetValue(property.Name, out cachedProperty))
                    {
                        Write(cachedProperty.CacheFieldName);
                    }
                    else
                    {
                        Write($"{nativePointer}->{nativeMethod.Field.Name}");
                    }
                }
                else if (property.Setter != null && method.Equals(property.Setter))
                {
                    var param     = method.Parameters[0];
                    var paramType = param.Native.Type;
                    var fieldSet  = BulletParser.GetTypeMarshalFieldSetCppCli(nativeMethod.Field, param, nativePointer);
                    if (!string.IsNullOrEmpty(fieldSet))
                    {
                        Write(fieldSet);
                    }
                    else
                    {
                        Write($"{nativePointer}->{nativeMethod.Field.Name} = ");
                        switch (paramType.Kind)
                        {
                        case TypeKind.Pointer:
                        case TypeKind.LValueReference:
                            if (paramType.Kind == TypeKind.LValueReference)
                            {
                                // Dereference
                                Write('*');
                            }

                            if (paramType.Referenced.Target != null &&
                                paramType.Referenced.Target.BaseClass != null)
                            {
                                // Cast native pointer from base class
                                Write($"({paramType.Referenced.FullName}*)");
                            }
                            break;
                        }
                        Write(param.Name);
                        if (!paramType.IsBasic)
                        {
                            Write("->_native");
                        }
                    }
                }
            }
            else
            {
                if (nativeMethod.IsConstructor)
                {
                }
                else if (nativeMethod.IsStatic)
                {
                    Write(parentClass.FullyQualifiedName + "::");
                }
                else
                {
                    Write(nativePointer + "->");
                }
                To = WriteTo.Source;
                WriteMethodMarshal(method, numParameters);
            }
            if (!nativeMethod.IsConstructor && !nativeMethod.IsVoid)
            {
                Write(BulletParser.GetTypeMarshalConstructorEnd(nativeMethod));
            }
            WriteLine(';');

            // Write type marshalling epilogue
            if (needTypeMarshalEpilogue)
            {
                foreach (var param in method.Parameters)
                {
                    string epilogue = BulletParser.GetTypeMarshalEpilogueCppCli(param);
                    if (!string.IsNullOrEmpty(epilogue))
                    {
                        WriteLine(1, epilogue);
                    }
                }
                if (!nativeMethod.IsVoid)
                {
                    WriteLine(1, "return ret;");
                }
            }
        }
        void OutputClass(ClassDefinition @class, int level)
        {
            EnsureHeaderWhiteSpace();
            EnsureSourceWhiteSpace();

            // Write access modifier
            WriteTabs(level);
            if (level == 1)
            {
                HeaderWrite("public ");
            }

            // Write class definition
            HeaderWrite(string.Format("ref class {0}", @class.ManagedName));
            if (@class.IsAbstract)
            {
                HeaderWrite(" abstract");
            }
            else if (@class.IsStaticClass)
            {
                HeaderWrite(" sealed");
            }
            if (@class.BaseClass != null)
            {
                HeaderWriteLine(string.Format(" : {0}", @class.BaseClass.ManagedName));
            }
            else if (@class.IsTrackingDisposable)
            {
                HeaderWriteLine(" : ITrackingDisposable");
            }
            else
            {
                // In C++/CLI, IDisposable is inherited automatically if the destructor and finalizer are defined
                //HeaderWrite(" : IDisposable");
                HeaderWriteLine();
            }

            WriteTabs(level);
            HeaderWriteLine("{");
            //hasHeaderWhiteSpace = true;

            // Default access for ref class
            var currentAccess = RefAccessSpecifier.Private;

            // Write child classes
            if ([email protected](cl => IsExcludedClass(cl)))
            {
                OutputClasses(@class.Classes, ref currentAccess, level);
                currentAccess = RefAccessSpecifier.Public;
                SourceWriteLine();
            }

            // Add a private constructor for classes without instances
            if (@class.IsStaticClass)
            {
                EnsureAccess(level, ref currentAccess, RefAccessSpecifier.Private);
                WriteTabs(level + 1);
                HeaderWriteLine(string.Format("{0}() {{}}", @class.ManagedName));
                hasHeaderWhiteSpace = false;
            }

            // Downcast native pointer if any methods in a derived class use it
            if (@class.BaseClass != null && @class.Methods.Any(m => !m.IsConstructor && !m.IsStatic))
            {
                EnsureSourceWhiteSpace();
                SourceWriteLine(string.Format("#define Native static_cast<{0}*>(_native)", @class.FullyQualifiedName));
                hasSourceWhiteSpace = false;
            }

            // Write the native pointer to the base class
            if (@class.BaseClass == null && [email protected])
            {
                if (@class.Classes.Any(c => !IsExcludedClass(c)))
                {
                    HeaderWriteLine();
                }
                if (@class.IsTrackingDisposable)
                {
                    EnsureAccess(level, ref currentAccess, RefAccessSpecifier.Public);
                    WriteTabs(level + 1);
                    HeaderWriteLine("virtual event EventHandler^ OnDisposing;");
                    WriteTabs(level + 1);
                    HeaderWriteLine("virtual event EventHandler^ OnDisposed;");
                    hasHeaderWhiteSpace = false;
                }
                EnsureAccess(level, ref currentAccess, RefAccessSpecifier.Internal);

                WriteTabs(level + 1);
                HeaderWrite(@class.FullyQualifiedName);
                HeaderWriteLine("* _native;");
                hasHeaderWhiteSpace = false;
            }

            EnsureHeaderWhiteSpace();
            EnsureSourceWhiteSpace();

            // Private fields
            // _isDisposed flag
            if (@class.IsTrackingDisposable)
            {
                EnsureAccess(level, ref currentAccess, RefAccessSpecifier.Private);
                WriteTabs(level + 1);
                HeaderWriteLine("bool _isDisposed;");
                hasHeaderWhiteSpace = false;
            }
            // _preventDelete flag
            if (@class.HasPreventDelete)
            {
                EnsureAccess(level, ref currentAccess, RefAccessSpecifier.Private);
                WriteTabs(level + 1);
                HeaderWriteLine("bool _preventDelete;");
                hasHeaderWhiteSpace = false;
            }

            // Write cached property fields
            foreach (var cachedProperty in @class.CachedProperties.OrderBy(p => p.Key))
            {
                EnsureAccess(level, ref currentAccess, cachedProperty.Value.Access);
                WriteTabs(level + 1);
                string name = cachedProperty.Key;
                name = char.ToLower(name[0]) + name.Substring(1);
                HeaderWriteLine(string.Format("{0} _{1};",
                                              BulletParser.GetTypeRefName(cachedProperty.Value.Property.Type), name));
                hasHeaderWhiteSpace = false;
            }

            // Write constructors and destructors if not static
            if ([email protected])
            {
                // Write unmanaged constructor
                // TODO: Write constructor from unmanaged pointer only if the class is ever instantiated in this way.
                if ([email protected])
                {
                    EnsureAccess(level, ref currentAccess, RefAccessSpecifier.Internal);

                    WriteTabs(level + 1);
                    SourceWrite(string.Format("{0}::", @class.FullNameManaged));
                    Write(string.Format("{0}({1}* native)", @class.ManagedName, @class.FullyQualifiedName));
                    HeaderWriteLine(';');
                    SourceWriteLine();
                    if (@class.BaseClass != null)
                    {
                        WriteTabs(1, true);
                        SourceWriteLine(string.Format(": {0}(native)", @class.BaseClass.ManagedName));
                    }
                    SourceWriteLine('{');
                    if (@class.BaseClass == null)
                    {
                        WriteTabs(1, true);
                        SourceWriteLine("_native = native;");
                    }
                    SourceWriteLine('}');
                    hasHeaderWhiteSpace = false;
                    hasSourceWhiteSpace = false;
                }

                // Write destructor & finalizer
                if (@class.BaseClass == null)
                {
                    // ECMA-372 19.13.2: "The access-specifier of a finalizer in a ref class is ignored."
                    WriteTabs(level + 1);
                    HeaderWriteLine(string.Format("!{0}();", @class.ManagedName));
                    // ECMA-372 19.13.1: "The access-specifier of a destructor in a ref class is ignored."
                    WriteTabs(level + 1);
                    HeaderWriteLine(string.Format("~{0}();", @class.ManagedName));
                    hasHeaderWhiteSpace = false;

                    EnsureSourceWhiteSpace();
                    SourceWriteLine(string.Format("{0}::~{1}()", @class.FullNameManaged, @class.ManagedName));
                    SourceWriteLine('{');
                    SourceWriteLine(string.Format("\tthis->!{0}();", @class.ManagedName));
                    SourceWriteLine('}');
                    SourceWriteLine();

                    SourceWriteLine(string.Format("{0}::!{1}()", @class.FullNameManaged, @class.ManagedName));
                    SourceWriteLine('{');
                    if (@class.IsTrackingDisposable)
                    {
                        SourceWriteLine("\tif (this->IsDisposed)");
                        SourceWriteLine("\t\treturn;");
                        SourceWriteLine();
                        SourceWriteLine("\tOnDisposing(this, nullptr);");
                        SourceWriteLine();
                    }
                    if (@class.HasPreventDelete)
                    {
                        SourceWriteLine("\tif (!_preventDelete)");
                        SourceWriteLine("\t{");
                        SourceWriteLine("\t\tdelete _native;");
                        SourceWriteLine("\t}");
                    }
                    else
                    {
                        SourceWriteLine("\tdelete _native;");
                    }
                    if (@class.IsTrackingDisposable)
                    {
                        SourceWriteLine("\t_isDisposed = true;");
                        SourceWriteLine();
                        SourceWriteLine("\tOnDisposed(this, nullptr);");
                    }
                    else
                    {
                        SourceWriteLine("\t_native = NULL;");
                    }
                    SourceWriteLine('}');
                    hasSourceWhiteSpace = false;
                }

                // Write public constructors
                if ([email protected] && [email protected])
                {
                    EnsureAccess(level, ref currentAccess, RefAccessSpecifier.Public);

                    var constructors = @class.Methods.Where(m => m.IsConstructor);
                    if (constructors.Any())
                    {
                        foreach (var constructor in constructors)
                        {
                            OutputMethod(constructor, level);
                        }
                    }
                    else
                    {
                        // Default constructor
                        MethodDefinition constructor = new MethodDefinition(@class.Name, @class, 0);
                        constructor.IsConstructor = true;
                        OutputMethod(constructor, level);
                    }
                }
            }

            // Write non-constructor methods
            var methods = @class.Methods.Where(m => !m.IsConstructor);

            if (methods.Any())
            {
                EnsureHeaderWhiteSpace();

                foreach (var method in methods)
                {
                    if (method.Property != null)
                    {
                        continue;
                    }

                    EnsureAccess(level, ref currentAccess, RefAccessSpecifier.Public);
                    OutputMethod(method, level);
                }
            }

            // Write properties (includes unmanaged fields and getters/setters)
            foreach (PropertyDefinition prop in @class.Properties)
            {
                string typeConditional = GetTypeConditional(prop.Type, @class.Header);
                if (typeConditional != null)
                {
                    WriteLine(string.Format("#ifndef {0}", typeConditional));
                    hasSourceWhiteSpace = true;
                }
                else
                {
                    EnsureHeaderWhiteSpace();
                }

                EnsureAccess(level, ref currentAccess, RefAccessSpecifier.Public);

                WriteTabs(level + 1);
                HeaderWriteLine(string.Format("property {0} {1}",
                                              BulletParser.GetTypeRefName(prop.Type), prop.Name));
                WriteTabs(level + 1);
                HeaderWriteLine("{");

                // Getter/Setter
                OutputMethod(prop.Getter, level + 1);
                if (prop.Setter != null)
                {
                    OutputMethod(prop.Setter, level + 1);
                }

                WriteTabs(level + 1);
                HeaderWriteLine("}");

                if (typeConditional != null)
                {
                    WriteLine("#endif");
                    hasSourceWhiteSpace = false;
                }

                hasHeaderWhiteSpace = false;
            }

            WriteTabs(level);
            HeaderWriteLine("};");
            hasHeaderWhiteSpace = false;
        }
        void OutputMethod(MethodDefinition method, int level, int numOptionalParams = 0)
        {
            var parentClass = method.Parent;

            // No whitespace between get/set methods
            if (!(method.Property != null &&
                  method.Equals(method.Property.Setter)))
            {
                EnsureSourceWhiteSpace();
                hasHeaderWhiteSpace = false;
            }

            // #ifndef DISABLE_FEATURE
            bool hasConditional = false;

            if (method.Property == null)
            {
                foreach (var param in method.Parameters)
                {
                    string typeConditional = GetTypeConditional(param.Type, parentClass.Header);
                    if (typeConditional != null)
                    {
                        WriteLine(string.Format("#ifndef {0}", typeConditional));
                        hasSourceWhiteSpace = true;
                        hasConditional      = true;
                    }
                }
            }

            WriteTabs(level + 1);

            // "static"
            if (method.IsStatic)
            {
                HeaderWrite("static ");
            }

            // Definition: return type
            if (!method.IsConstructor)
            {
                var returnType = method.ReturnType;

                if (method.Property != null)
                {
                    if (method.Equals(method.Property.Getter))
                    {
                        // If property name matches type name, resolve ambiguity
                        if (method.Property.Name.Equals(method.Property.Type.ManagedName))
                        {
                            HeaderWrite(NamespaceName + "::");
                        }

                        // Getter with parameter for return value
                        if (method.Parameters.Length == 1)
                        {
                            returnType = method.Parameters[0].Type;
                        }
                    }
                }

                Write(BulletParser.GetTypeRefName(returnType));
                Write(' ');
            }

            // Definition: name
            string headerMethodName;
            string sourceMethodName;

            if (method.IsConstructor)
            {
                headerMethodName = parentClass.ManagedName;
                sourceMethodName = headerMethodName;
            }
            else if (method.Property != null)
            {
                headerMethodName = method.Property.Getter.Equals(method) ? "get" : "set";
                sourceMethodName = string.Format("{0}::{1}", method.Property.Name, headerMethodName);
            }
            else
            {
                headerMethodName = method.ManagedName;
                sourceMethodName = headerMethodName;
            }
            HeaderWrite(string.Format("{0}(", headerMethodName));
            SourceWrite(string.Format("{0}::{1}(", parentClass.FullNameManaged, sourceMethodName));

            // Definition: parameters
            int numParameters = method.Parameters.Length - numOptionalParams;

            // Getters with parameter for return value
            if (numParameters == 1 && method.Property != null && method.Equals(method.Property.Getter))
            {
                numParameters = 0;
            }
            bool hasOptionalParam = false;

            for (int i = 0; i < numParameters; i++)
            {
                var param = method.Parameters[i];
                Write(string.Format("{0} {1}",
                                    BulletParser.GetTypeRefName(param.Type), param.ManagedName));

                if (param.IsOptional)
                {
                    hasOptionalParam = true;
                }

                if (i != numParameters - 1)
                {
                    if (_headerLineLength >= LineBreakWidth)
                    {
                        HeaderWriteLine(",");
                        WriteTabs(level + 2);
                    }
                    else
                    {
                        HeaderWrite(", ");
                    }

                    if (_sourceLineLength >= LineBreakWidth)
                    {
                        SourceWriteLine(",");
                        WriteTabs(1, true);
                    }
                    else
                    {
                        SourceWrite(", ");
                    }
                }
            }
            HeaderWriteLine(");");
            SourceWriteLine(')');


            // Constructor chaining
            bool doConstructorChaining = false;

            if (method.IsConstructor && parentClass.BaseClass != null)
            {
                // If there is no need for marshalling code, we can chain constructors
                doConstructorChaining = method.Parameters.All(p => !BulletParser.TypeRequiresMarshal(p.Type));

                WriteTabs(1, true);
                SourceWrite(string.Format(": {0}(", parentClass.BaseClass.ManagedName));

                if (doConstructorChaining)
                {
                    SourceWrite("new ");
                    OutputMethodMarshal(method, numParameters);
                    if (parentClass.BaseClass.HasPreventDelete)
                    {
                        SourceWrite(", false");
                    }
                }
                else
                {
                    SourceWrite('0');
                }

                SourceWriteLine(')');
            }

            // Method definition
            SourceWriteLine('{');
            if (!doConstructorChaining)
            {
                WriteMethodDefinition(method, numParameters);
            }
            // Cache property values
            if (method.IsConstructor)
            {
                var assignments  = new List <string>();
                var methodParent = method.Parent;
                while (methodParent != null)
                {
                    foreach (var cachedProperty in methodParent.CachedProperties.OrderBy(p => p.Key))
                    {
                        foreach (var param in method.Parameters)
                        {
                            if (param.ManagedName.ToLower() == cachedProperty.Key.ToLower() &&
                                param.Type.ManagedName == cachedProperty.Value.Property.Type.ManagedName)
                            {
                                string assignment = string.Format("\t{0} = {1};", cachedProperty.Value.CacheFieldName, param.ManagedName);
                                assignments.Add(assignment);
                            }
                        }
                    }
                    methodParent = methodParent.BaseClass;
                }
                if (assignments.Count != 0)
                {
                    EnsureSourceWhiteSpace();
                    foreach (string assignment in assignments)
                    {
                        SourceWriteLine(assignment);
                    }
                    hasSourceWhiteSpace = false;
                }
            }
            SourceWriteLine('}');
            hasSourceWhiteSpace = false;

            // #endif // DISABLE_FEATURE
            if (hasConditional)
            {
                foreach (var param in method.Parameters)
                {
                    string typeConditional = GetTypeConditional(param.Type, method.Parent.Header);
                    if (typeConditional != null)
                    {
                        WriteLine("#endif");
                        hasHeaderWhiteSpace = true;
                    }
                }
            }

            // If there are optional parameters, then output all possible combinations of calls
            if (hasOptionalParam)
            {
                OutputMethod(method, level, numOptionalParams + 1);
            }
        }
        void WriteMethodDefinition(MethodDefinition method, int numParameters)
        {
            var parentClass = method.Parent;

            // Type marshalling prologue
            bool needTypeMarshalEpilogue = false;

            if (method.Field == null)
            {
                foreach (var param in method.Parameters)
                {
                    string prologue = BulletParser.GetTypeMarshalPrologueCppCli(param);
                    if (!string.IsNullOrEmpty(prologue))
                    {
                        WriteTabs(1, true);
                        SourceWriteLine(prologue);
                    }

                    // Do we need a type marshalling epilogue?
                    if (!needTypeMarshalEpilogue)
                    {
                        string epilogue = BulletParser.GetTypeMarshalEpilogueCppCli(param);
                        if (!string.IsNullOrEmpty(epilogue))
                        {
                            needTypeMarshalEpilogue = true;
                        }
                    }
                }
            }

            WriteTabs(1, true);
            if (method.IsConstructor)
            {
                SourceWrite("_native = new ");
            }
            else if (!method.IsVoid)
            {
                //if (method.ReturnType.IsBasic || method.ReturnType.Referenced != null)
                if (needTypeMarshalEpilogue)
                {
                    // Return after epilogue (cleanup)
                    SourceWrite(string.Format("{0} ret = ",
                                              BulletParser.GetTypeRefName(method.ReturnType)));
                }
                else
                {
                    // Return immediately
                    SourceWrite("return ");
                }
                SourceWrite(BulletParser.GetTypeMarshalConstructorStart(method));
            }
            else if (method.Property != null && method.Equals(method.Property.Getter))
            {
                SourceWrite(BulletParser.GetTypeMarshalConstructorStart(method));
            }

            // Native is defined as static_cast<className*>(_native)
            string nativePointer = (parentClass.BaseClass != null) ? "Native" : "_native";

            if (method.Field != null)
            {
                var property = method.Property;
                if (method.Equals(property.Getter))
                {
                    CachedProperty cachedProperty;
                    if (method.Parent.CachedProperties.TryGetValue(property.Name, out cachedProperty))
                    {
                        SourceWrite(cachedProperty.CacheFieldName);
                    }
                    else
                    {
                        SourceWrite(string.Format("{0}->{1}", nativePointer, method.Field.Name));
                    }
                }
                else if (property.Setter != null && method.Equals(property.Setter))
                {
                    var param    = method.Parameters[0];
                    var fieldSet = BulletParser.GetTypeMarshalFieldSetCppCli(method.Field, param, nativePointer);
                    if (!string.IsNullOrEmpty(fieldSet))
                    {
                        SourceWrite(fieldSet);
                    }
                    else
                    {
                        SourceWrite(string.Format("{0}->{1} = ", nativePointer, method.Field.Name));
                        if (param.Type.IsPointer || param.Type.IsReference)
                        {
                            if (param.Type.IsReference)
                            {
                                // Dereference
                                SourceWrite('*');
                            }

                            if (param.Type.Referenced.Target != null &&
                                param.Type.Referenced.Target.BaseClass != null)
                            {
                                // Cast native pointer from base class
                                SourceWrite(string.Format("({0}*)", param.Type.Referenced.FullName));
                            }
                        }
                        SourceWrite(param.ManagedName);
                        if (!param.Type.IsBasic)
                        {
                            SourceWrite("->_native");
                        }
                    }
                }
            }
            else
            {
                if (method.IsConstructor)
                {
                }
                else if (method.IsStatic)
                {
                    SourceWrite(parentClass.FullyQualifiedName + "::");
                }
                else
                {
                    SourceWrite(nativePointer + "->");
                }
                OutputMethodMarshal(method, numParameters);
            }
            if (!method.IsConstructor && !method.IsVoid)
            {
                SourceWrite(BulletParser.GetTypeMarshalConstructorEnd(method));
            }
            SourceWriteLine(';');

            // Write type marshalling epilogue
            if (needTypeMarshalEpilogue)
            {
                foreach (var param in method.Parameters)
                {
                    string epilogue = BulletParser.GetTypeMarshalEpilogueCppCli(param);
                    if (!string.IsNullOrEmpty(epilogue))
                    {
                        WriteTabs(1, true);
                        SourceWriteLine(epilogue);
                    }
                }
                if (!method.IsVoid)
                {
                    WriteTabs(1, true);
                    SourceWriteLine("return ret;");
                }
            }
        }