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; }
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); } }
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 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 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;"); } } }