public MethodDefinition(string name, ClassDefinition parent, int numArgs) { Name = name; Parent = parent; Parameters = new ParameterDefinition[numArgs]; if (parent != null) { parent.Methods.Add(this); } }
public MethodDefinition Copy(ClassDefinition parent = null) { var m = new MethodDefinition(Name, parent ?? Parent, Parameters.Length) { Access = Access, Field = Field, IsAbstract = IsAbstract, IsConstructor = IsConstructor, IsExcluded = IsExcluded, IsStatic = IsStatic, OutValueParameter = OutValueParameter?.Copy(), ReturnType = ReturnType.Copy() }; for (int i = 0; i < Parameters.Length; i++) { m.Parameters[i] = Parameters[i].Copy(); } return m; }
bool ClassNeedsExtensions(ClassDefinition c) { foreach (var prop in c.Properties) { if (_extensionClassesInternal.ContainsKey(prop.Type.ManagedName)) { return true; } } foreach (var method in c.Methods) { if (MethodNeedsExtensions(method)) { return true; } } return false; }
private static bool RequiresMathNamespace(ClassDefinition @class) { if (@class.NestedClasses.Any(RequiresMathNamespace)) return true; if (@class.IsExcluded) return false; foreach (var method in @class.Methods.Where(m => !m.IsExcluded)) { if (@class.HidePublicConstructors && method.IsConstructor) continue; if (DefaultParser.TypeRequiresMarshal(method.ReturnType)) return true; if (method.Parameters.Any(param => DefaultParser.TypeRequiresMarshal(param.Type))) { return true; } } return false; }
public EnumDefinition(string name, HeaderDefinition header = null, ClassDefinition parent = null) : base(name, header, parent) { EnumConstants = new List<string>(); EnumConstantValues = new List<string>(); }
bool IsExcludedClass(ClassDefinition c) { return c.IsTypedef || c.IsPureEnum || c.IsExcluded; }
private void CopyTemplateMethods(ClassDefinition thisClass, ClassTemplateDefinition template, Dictionary <string, string> templateParams = null) { if (templateParams == null) { templateParams = new Dictionary <string, string>(); var templateBase = template.BaseClass as ClassTemplateDefinition; for (int i = 0; i < template.TemplateParameters.Count; i++) { string param = templateBase.TemplateParameters[i]; string paramValue = template.TemplateParameters[i]; templateParams[param] = paramValue; } CopyTemplateMethods(thisClass, templateBase, templateParams); return; } thisClass.BaseClass = template.BaseClass; var scriptedNameMapping = Project.ClassNameMapping as ScriptedMapping; if (scriptedNameMapping != null) { scriptedNameMapping.Globals.Header = thisClass.Header; } // TODO: //template.ManagedName = Project.ClassNameMapping.Map(template.Name); foreach (var templateClass in template.NestedClasses) { var classSpec = new ClassDefinition(templateClass.Name, thisClass.Header, thisClass); Project.ClassDefinitions.Add(classSpec.FullyQualifiedName, classSpec); foreach (var templateMethod in templateClass.Methods) { // Replace template parameters with concrete types var methodSpec = templateMethod.Copy(classSpec); if (methodSpec.ReturnType.HasTemplateTypeParameter) { methodSpec.ReturnType = methodSpec.ReturnType.CopyTemplated(templateParams); } foreach (var param in methodSpec.Parameters .Where(p => p.Type.HasTemplateTypeParameter)) { param.Type = param.Type.CopyTemplated(templateParams); } } } foreach (var templateMethod in template.Methods.Where(m => !m.IsConstructor)) { // Replace template parameters with concrete types var methodSpec = templateMethod.Copy(thisClass); if (methodSpec.ReturnType.HasTemplateTypeParameter) { methodSpec.ReturnType = methodSpec.ReturnType.CopyTemplated(templateParams); } foreach (var param in methodSpec.Parameters .Where(p => p.Type.HasTemplateTypeParameter)) { param.Type = param.Type.CopyTemplated(templateParams); } } }
private static bool RequiresConversionHeader(ClassDefinition @class) { if (@class.NestedClasses.Any(RequiresConversionHeader)) return true; foreach (var method in @class.Methods.Where(m => !m.IsExcluded)) { if (DefaultParser.TypeRequiresMarshal(method.ReturnType)) return true; if (method.Parameters.Any(p => DefaultParser.TypeRequiresMarshal(p.Type))) return true; } return false; }
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; }
private static bool RequiresConversionHeader(ClassDefinition cl) { if (cl.Classes.Any(RequiresConversionHeader)) { return true; } foreach (var method in cl.Methods) { if (BulletParser.TypeRequiresMarshal(method.ReturnType)) { return true; } foreach (var param in method.Parameters) { if (BulletParser.TypeRequiresMarshal(param.Type)) { return true; } } } return false; }
void WriteClass(ClassDefinition @class, int level) { if (_wrapperHeaderGuards.ContainsKey(@class.Name)) { WriteWrapperClassConstructor(@class); } // Write child classes foreach (var c in @class.NestedClasses .Where(c => !IsExcludedClass(c)) .OrderBy(c => c.Name)) { WriteClass(c, level + 1); } // Group methods into constructors, destructors and methods var methodGroups = @class.Methods.GroupBy(m => { if (m.IsExcluded) { return((CursorKind)0); } if (m.IsConstructor) { return(CursorKind.Constructor); } if (m.IsDestructor) { return(CursorKind.Destructor); } return(CursorKind.CxxMethod); }).ToDictionary(g => g.Key); // Constructors if ([email protected] && [email protected] && [email protected]) { IGrouping <CursorKind, MethodDefinition> constructors; if (methodGroups.TryGetValue(CursorKind.Constructor, out constructors)) { int overloadIndex = 0; foreach (var constructor in methodGroups[CursorKind.Constructor]) { WriteMethod(constructor, level, ref overloadIndex); } } } // Methods IGrouping <CursorKind, MethodDefinition> methods; if (methodGroups.TryGetValue(CursorKind.CxxMethod, out methods)) { foreach (var groupByName in methods.GroupBy(m => m.Name)) { int overloadIndex = 0; foreach (var method in groupByName) { WriteMethod(method, level, ref overloadIndex); } } } // Destructors IGrouping <CursorKind, MethodDefinition> destructors; if (methodGroups.TryGetValue(CursorKind.Destructor, out destructors)) { int overloadIndex = 0; foreach (var method in destructors) { WriteMethod(method, level, ref overloadIndex); } } _hasCppClassSeparatingWhitespace = false; }
public ClassTemplateDefinition(string name, HeaderDefinition header = null, ClassDefinition parent = null) : base(name, header, parent) { }
public ManagedClass(ClassDefinition nativeClass, string managedName, ManagedClass parent) { Native = nativeClass; Name = managedName; Parent = parent; }
public EnumDefinition(string name, HeaderDefinition header = null, ClassDefinition parent = null) : base(name, header, parent) { EnumConstants = new List <string>(); EnumConstantValues = new List <string>(); }
public ManagedClass GetManaged(ClassDefinition @class) { return(Classes[@class.FullyQualifiedName]); }
protected bool IsExcludedClass(ClassDefinition @class) { return(@class is ClassTemplateDefinition || @class is EnumDefinition || @class.IsPureEnum || @class.IsExcluded || @class.IsFunctionProto); }
public ClassDefinition(string name, ClassDefinition parent) : this(name, parent.Header) { Parent = parent; }
public void WriteClassWrapper(ClassDefinition cl) { List<MethodDefinition> baseAbstractMethods; List<MethodDefinition> thisAbstractMethods = cl.Methods.Where(x => x.IsVirtual).ToList(); List<MethodDefinition> abstractMethods = thisAbstractMethods.ToList(); if (cl.BaseClass != null) { baseAbstractMethods = cl.BaseClass.Target.Methods.Where(x => x.IsVirtual).ToList(); abstractMethods.AddRange(baseAbstractMethods); } else { baseAbstractMethods = new List<MethodDefinition>(); } if (!hasClassSeparatingWhitespace) { WriteLine(WriteTo.Header | WriteTo.Source); hasClassSeparatingWhitespace = true; } EnsureWhiteSpace(WriteTo.Source); // Wrapper C Constructor Write("\tEXPORT ", WriteTo.Header); Write(string.Format("{0}Wrapper* {0}Wrapper_new(", cl.Name), WriteTo.Header | WriteTo.Source); int numMethods = abstractMethods.Count; for (int i = 0; i < numMethods; i++) { var method = abstractMethods[i]; string className = baseAbstractMethods.Contains(method) ? cl.BaseClass.ManagedName : cl.ManagedName; Write(string.Format("p{0}_{1} {2}Callback", className, method.ManagedName, method.Name), WriteTo.Header | WriteTo.Source); if (i != numMethods - 1) { Write(", ", WriteTo.Header | WriteTo.Source); } } WriteLine(");", WriteTo.Header); WriteLine(')', WriteTo.Source); WriteLine('{', WriteTo.Source); Write(string.Format("\treturn new {0}Wrapper(", cl.Name), WriteTo.Source); for (int i = 0; i < numMethods; i++) { var method = abstractMethods[i]; Write(string.Format("{0}Callback", method.Name), WriteTo.Source); if (i != numMethods - 1) { Write(", ", WriteTo.Source); } } WriteLine(");", WriteTo.Source); WriteLine('}', WriteTo.Source); hasClassSeparatingWhitespace = false; hasSourceWhiteSpace = false; }
public void WriteClassWrapperMethodDeclarations(ClassDefinition cl) { List<MethodDefinition> baseAbstractMethods; List<MethodDefinition> thisAbstractMethods = cl.Methods.Where(x => x.IsVirtual).ToList(); List<MethodDefinition> abstractMethods = thisAbstractMethods.ToList(); if (cl.BaseClass != null) { baseAbstractMethods = cl.BaseClass.Target.Methods.Where(x => x.IsVirtual).ToList(); abstractMethods.AddRange(baseAbstractMethods); } else { baseAbstractMethods = new List<MethodDefinition>(); } if (!hasClassSeparatingWhitespace) { WriteLine(WriteTo.Header); hasClassSeparatingWhitespace = true; } string headerGuard = wrapperHeaderGuards[cl.Name]; foreach (MethodDefinition method in thisAbstractMethods) { Write(string.Format("typedef {0} (*p{1}_{2})(", method.ReturnType.Name, cl.ManagedName, method.ManagedName), WriteTo.Header); int numParameters = method.Parameters.Length; for (int i = 0; i < numParameters; i++) { var param = method.Parameters[i]; WriteType(param.Type, WriteTo.Header); Write(" ", WriteTo.Header); Write(param.Name, WriteTo.Header); if (i != numParameters - 1) { Write(", ", WriteTo.Header); } } WriteLine(");", WriteTo.Header); } if (thisAbstractMethods.Count != 0) { WriteLine(WriteTo.Header); } WriteLine(string.Format("class {0}Wrapper : public {0}", cl.FullNameCS), WriteTo.Header); WriteLine("{", WriteTo.Header); WriteLine("private:", WriteTo.Header); foreach (MethodDefinition method in abstractMethods) { string className = baseAbstractMethods.Contains(method) ? cl.BaseClass.ManagedName : cl.ManagedName; WriteLine(string.Format("\tp{0}_{1} _{2}Callback;", className, method.ManagedName, method.Name), WriteTo.Header); } WriteLine(WriteTo.Header); WriteLine("public:", WriteTo.Header); // Wrapper constructor Write(string.Format("\t{0}Wrapper(", cl.FullNameCS), WriteTo.Header); int numMethods = abstractMethods.Count; for (int i = 0; i < numMethods; i++) { var method = abstractMethods[i]; string className = baseAbstractMethods.Contains(method) ? cl.BaseClass.ManagedName : cl.ManagedName; Write(string.Format("p{0}_{1} {2}Callback", className, method.ManagedName, method.Name), WriteTo.Header); if (i != numMethods - 1) { Write(", ", WriteTo.Header); } } WriteLine(");", WriteTo.Header); WriteLine(WriteTo.Header); foreach (MethodDefinition method in abstractMethods) { Write(string.Format("\tvirtual {0} {1}(", method.ReturnType.Name, method.Name), WriteTo.Header); int numParameters = method.Parameters.Length; for (int i = 0; i < numParameters; i++) { var param = method.Parameters[i]; WriteType(param.Type, WriteTo.Header); Write(" ", WriteTo.Header); Write(param.Name, WriteTo.Header); if (i != numParameters - 1) { Write(", ", WriteTo.Header); } } WriteLine(");", WriteTo.Header); } WriteLine("};", WriteTo.Header); hasClassSeparatingWhitespace = false; }
public void WriteWrapperClass(ClassDefinition @class) { List <MethodDefinition> baseVirtualMethods; var thisVirtualMethods = @class.Methods.Where(x => x.IsVirtual).ToList(); var virtualMethods = thisVirtualMethods.ToList(); if (@class.BaseClass != null) { baseVirtualMethods = @class.BaseClass.Methods.Where(x => x.IsVirtual).ToList(); virtualMethods.AddRange(baseVirtualMethods); } else { baseVirtualMethods = new List <MethodDefinition>(); } var methodCallbacks = virtualMethods.Select(m => { string className = baseVirtualMethods.Contains(m) ? GetFullNameC(@class.BaseClass) : GetFullNameC(@class); return($"p_{className}_{m.Name} {m.Name}Callback"); }).ToList(); if (!_hasCppClassSeparatingWhitespace) { WriteLine(); _hasCppClassSeparatingWhitespace = true; } // TODO: string headerGuard = wrapperHeaderGuards[@class.Name]; string parameters; if (thisVirtualMethods.Count != 0) { foreach (var method in thisVirtualMethods) { string methodPtr = $"p_{GetFullNameC(@class)}_{method.Name}"; Write($"typedef {method.ReturnType.Name} (*{methodPtr})(", WriteTo.Header); parameters = ListToLines(method.Parameters .Select(p => $"{GetTypeNameC(p.Type)} {p.Name}"), WriteTo.Header); WriteLine($"{parameters});", WriteTo.Header); } WriteLine(); } // Wrapper class string wrapperClassName = $"{GetFullNameC(@class)}Wrapper"; WriteLine($"class {wrapperClassName} : public {GetFullNameC(@class)}"); WriteLine("{"); WriteLine("private:"); foreach (var m in virtualMethods) { string className = baseVirtualMethods.Contains(m) ? GetFullNameC(@class.BaseClass) : GetFullNameC(@class); WriteLine(1, $"p_{className}_{m.Name} _{m.Name}Callback;"); } WriteLine(); WriteLine("public:"); // Wrapper constructor Write(1, $"{wrapperClassName}("); string constructorParams = ListToLines(methodCallbacks, WriteTo.Header, 1); WriteLine($"{constructorParams});"); WriteLine(); // Wrapper methods foreach (var m in virtualMethods) { Write(1, $"virtual {m.ReturnType.Name} {m.Name}("); string methodParams = ListToLines( m.Parameters.Select(p => $"{GetTypeNameC(p.Type)} {p.Name}"), WriteTo.Header, 1); WriteLine(methodParams + ");"); } WriteLine("};"); _hasCppClassSeparatingWhitespace = false; var prevTo = To; To = WriteTo.Source; EnsureWhiteSpace(); // Wrapper C++ Constructor Write($"{wrapperClassName}::{wrapperClassName}("); parameters = ListToLines(methodCallbacks, WriteTo.Source); WriteLine($"{parameters})"); WriteLine('{'); foreach (var method in virtualMethods) { WriteLine(1, string.Format("_{0}Callback = {0}Callback;", method.Name)); } WriteLine('}'); WriteLine(); // Wrapper C++ methods foreach (var method in virtualMethods) { Write($"{method.ReturnType.Name} {wrapperClassName}::{method.Name}("); parameters = ListToLines(method.Parameters .Select(p => $"{GetTypeNameC(p.Type)} {p.Name}"), WriteTo.Source); WriteLine($"{parameters})"); WriteLine('{'); WriteTabs(1); if (!method.IsVoid) { Write("return "); } Write($"_{method.Name}Callback("); parameters = ListToLines(method.Parameters .Select(p => p.Name), WriteTo.Source, 1); WriteLine($"{parameters});"); WriteLine('}'); WriteLine(); } WriteLine(); To = prevTo; }
void WriteClass(ClassDefinition c, int level) { if (c.IsExcluded || c.IsTypedef || c.IsPureEnum) { return; } if (wrapperHeaderGuards.ContainsKey(c.Name)) { WriteClassWrapper(c); } EnsureWhiteSpace(WriteTo.Source | WriteTo.CS); // Write class definition WriteTabs(level, WriteTo.CS); Write("public class ", WriteTo.CS); Write(c.ManagedName, WriteTo.CS); if (c.BaseClass != null) { Write(" : ", WriteTo.CS); WriteLine(c.BaseClass.Target.FullNameManaged.Replace("::", "."), WriteTo.CS); //WriteLine(c.BaseClass.ManagedNameCS, WriteTo.CS); } else { WriteLine(" : IDisposable", WriteTo.CS); } WriteTabs(level, WriteTo.CS); WriteLine("{", WriteTo.CS); hasCSWhiteSpace = true; // Write child classes foreach (ClassDefinition cl in c.Classes.OrderBy(x => x.FullNameManaged)) { WriteClass(cl, level + 1); } if (!hasClassSeparatingWhitespace) { WriteLine(WriteTo.Header | WriteTo.Source); hasClassSeparatingWhitespace = true; } // Write native pointer if (c.BaseClass == null) { EnsureWhiteSpace(WriteTo.CS); WriteTabs(level + 1, WriteTo.CS); WriteLine("internal IntPtr _native;", WriteTo.CS); if (c.HasPreventDelete) { WriteTabs(level + 1, WriteTo.CS); WriteLine("bool _preventDelete;", WriteTo.CS); hasCSWhiteSpace = false; } hasCSWhiteSpace = false; } // Write methods int overloadIndex = 0; bufferBuilder.Clear(); // Write C# internal constructor if (!c.NoInternalConstructor) { EnsureWhiteSpace(WriteTo.CS); WriteTabs(level + 1, WriteTo.CS); Write("internal ", WriteTo.CS); Write(c.ManagedName, WriteTo.CS); Write("(IntPtr native", WriteTo.CS); if (c.HasPreventDelete) { Write(", bool preventDelete", WriteTo.CS); } WriteLine(')', WriteTo.CS); if (c.BaseClass != null) { WriteTabs(level + 2, WriteTo.CS); Write(": base(native", WriteTo.CS); if (c.HasPreventDelete) { if (!c.BaseClass.Target.HasPreventDelete) { // Base class should also have preventDelete //throw new NotImplementedException(); } Write(", preventDelete", WriteTo.CS); } else { if (c.BaseClass.Target.HasPreventDelete) { Write(", true", WriteTo.CS); } } WriteLine(')', WriteTo.CS); } WriteTabs(level + 1, WriteTo.CS); WriteLine('{', WriteTo.CS); if (c.BaseClass == null) { WriteTabs(level + 2, WriteTo.CS); WriteLine("_native = native;", WriteTo.CS); if (c.HasPreventDelete) { WriteTabs(level + 2, WriteTo.CS); WriteLine("_preventDelete = preventDelete;", WriteTo.CS); } } WriteTabs(level + 1, WriteTo.CS); WriteLine('}', WriteTo.CS); hasCSWhiteSpace = false; } // Write constructors bool hasConstructors = false; if (!c.IsAbstract) { foreach (MethodDefinition method in c.Methods.Where(m => m.IsConstructor)) { if (!c.HidePublicConstructors) { WriteMethod(method, level, ref overloadIndex); } hasConstructors = true; } // Write default constructor if (!hasConstructors && !c.IsAbstract && !c.HidePublicConstructors) { var constructor = new MethodDefinition(c.Name, c, 0); constructor.IsConstructor = true; WriteMethod(constructor, level, ref overloadIndex); } overloadIndex = 0; } // Write methods MethodDefinition previousMethod = null; foreach (MethodDefinition method in c.Methods.Where(m => !m.IsConstructor).OrderBy(m => m.Name)) { if (previousMethod != null && previousMethod.Name != method.Name) { overloadIndex = 0; } WriteMethod(method, level, ref overloadIndex); previousMethod = method; } overloadIndex = 0; // Write properties foreach (PropertyDefinition prop in c.Properties) { WriteProperty(prop, level); } // Write delete method if (c.BaseClass == null) { var del = new MethodDefinition("delete", c, 0); del.ReturnType = new TypeRefDefinition(); WriteMethod(del, level, ref overloadIndex); c.Methods.Remove(del); overloadIndex = 0; } // Write DllImport clauses if (bufferBuilder.Length != 0) { EnsureWhiteSpace(WriteTo.CS); Write(bufferBuilder.ToString(), WriteTo.CS); } WriteTabs(level, WriteTo.CS); WriteLine("}", WriteTo.CS); hasCSWhiteSpace = false; hasClassSeparatingWhitespace = false; }
private void WriteClass(ClassDefinition c) { foreach (var child in c.Classes) { WriteClass(child); } if (!ClassNeedsExtensions(c)) { return; } _extensionMethods.Clear(); EnsureWhiteSpace(WriteTo.CS); WriteTabs(1, WriteTo.CS); csWriter.WriteLine("[EditorBrowsable(EditorBrowsableState.Never)]"); WriteTabs(1, WriteTo.CS); csWriter.WriteLine("public static class {0}Extensions", c.ManagedName); WriteTabs(1, WriteTo.CS); csWriter.WriteLine('{'); foreach (var prop in c.Properties) { if (_extensionClassesInternal.ContainsKey(prop.Type.ManagedName)) { // Getter with out parameter bufferBuilder.Clear(); WriteTabs(2, WriteTo.Buffer); WriteLine(string.Format("public unsafe static void Get{0}(this {1} obj, out {2} value)", prop.Name, c.ManagedName, _extensionClassesExternal[prop.Type.ManagedName]), WriteTo.Buffer); WriteTabs(2, WriteTo.Buffer); WriteLine('{', WriteTo.Buffer); WriteTabs(3, WriteTo.Buffer); WriteLine(string.Format("fixed ({0}* valuePtr = &value)", _extensionClassesExternal[prop.Type.ManagedName]), WriteTo.Buffer); WriteTabs(3, WriteTo.Buffer); WriteLine('{', WriteTo.Buffer); WriteTabs(4, WriteTo.Buffer); Write("*(", WriteTo.Buffer); Write(_extensionClassesInternal[prop.Type.ManagedName], WriteTo.Buffer); WriteLine(string.Format("*({0}*)valuePtr = obj.{1};", _extensionClassesInternal[prop.Type.ManagedName], prop.Name), WriteTo.Buffer); WriteTabs(3, WriteTo.Buffer); WriteLine('}', WriteTo.Buffer); WriteTabs(2, WriteTo.Buffer); WriteLine('}', WriteTo.Buffer); _extensionMethods.Add(new KeyValuePair <string, string>("Get" + prop.Name, bufferBuilder.ToString())); // Getter with return value bufferBuilder.Clear(); WriteTabs(2, WriteTo.Buffer); WriteLine(string.Format("public static {0} Get{1}(this {1} obj)", _extensionClassesExternal[prop.Type.ManagedName], prop.Name, c.ManagedName), WriteTo.Buffer); WriteTabs(2, WriteTo.Buffer); WriteLine('{', WriteTo.Buffer); WriteTabs(3, WriteTo.Buffer); WriteLine(string.Format("{0} value;", _extensionClassesExternal[prop.Type.ManagedName]), WriteTo.Buffer); WriteTabs(3, WriteTo.Buffer); WriteLine(string.Format("Get{0}(obj, out value)", prop.Name), WriteTo.Buffer); WriteTabs(3, WriteTo.Buffer); WriteLine("return value;", WriteTo.Buffer); WriteTabs(2, WriteTo.Buffer); WriteLine('}', WriteTo.Buffer); _extensionMethods.Add(new KeyValuePair <string, string>("Get" + prop.Name, bufferBuilder.ToString())); if (prop.Setter == null) { continue; } // Setter with ref parameter bufferBuilder.Clear(); WriteTabs(2, WriteTo.Buffer); WriteLine(string.Format("public unsafe static void Set{0}(this {1} obj, ref {2} value)", prop.Name, c.ManagedName, _extensionClassesExternal[prop.Type.ManagedName]), WriteTo.Buffer); WriteTabs(2, WriteTo.Buffer); WriteLine('{', WriteTo.Buffer); WriteTabs(3, WriteTo.Buffer); WriteLine(string.Format("fixed ({0}* valuePtr = &value)", _extensionClassesExternal[prop.Type.ManagedName]), WriteTo.Buffer); WriteTabs(3, WriteTo.Buffer); WriteLine('{', WriteTo.Buffer); WriteTabs(4, WriteTo.Buffer); WriteLine(string.Format("obj.{0} = *({1}*)valuePtr;", prop.Name, _extensionClassesInternal[prop.Type.ManagedName]), WriteTo.Buffer); WriteTabs(3, WriteTo.Buffer); WriteLine('}', WriteTo.Buffer); WriteTabs(2, WriteTo.Buffer); WriteLine('}', WriteTo.Buffer); _extensionMethods.Add(new KeyValuePair <string, string>("Set" + prop.Name, bufferBuilder.ToString())); // Setter with non-ref parameter bufferBuilder.Clear(); WriteTabs(2, WriteTo.Buffer); WriteLine(string.Format("public static void Set{0}(this {1} obj, {2} value)", prop.Name, c.ManagedName, _extensionClassesExternal[prop.Type.ManagedName]), WriteTo.Buffer); WriteTabs(2, WriteTo.Buffer); WriteLine('{', WriteTo.Buffer); WriteTabs(3, WriteTo.Buffer); WriteLine(string.Format("Set{0}(obj, ref value);", prop.Name), WriteTo.Buffer); WriteTabs(2, WriteTo.Buffer); WriteLine('}', WriteTo.Buffer); _extensionMethods.Add(new KeyValuePair <string, string>("Set" + prop.Name, bufferBuilder.ToString())); } } foreach (var method in c.Methods) { if (!MethodNeedsExtensions(method)) { continue; } WriteMethod(method); } foreach (var method in _extensionMethods.OrderBy(key => key.Key)) { EnsureWhiteSpace(WriteTo.CS); csWriter.Write(method.Value); hasCSWhiteSpace = false; } WriteTabs(1, WriteTo.CS); csWriter.WriteLine('}'); hasCSWhiteSpace = false; }
public void WriteWrapperClassConstructor(ClassDefinition @class) { List<MethodDefinition> baseVirtualMethods; var thisVirtualMethods = @class.Methods.Where(x => x.IsVirtual).ToList(); var virtualMethods = thisVirtualMethods.ToList(); if (@class.BaseClass != null) { baseVirtualMethods = @class.BaseClass.Methods.Where(x => x.IsVirtual).ToList(); virtualMethods.AddRange(baseVirtualMethods); } else { baseVirtualMethods = new List<MethodDefinition>(); } var methodCallbacks = virtualMethods.Select(m => { string className = baseVirtualMethods.Contains(m) ? GetFullNameC(@class.BaseClass) : GetFullNameC(@class); return $"p_{className}_{m.Name} {m.Name}Callback"; }).ToList(); if (!_hasCppClassSeparatingWhitespace) { WriteLine(WriteTo.Header | WriteTo.Source); _hasCppClassSeparatingWhitespace = true; } EnsureWhiteSpace(WriteTo.Source); // Wrapper C Constructor string wrapperClassName = $"{GetFullNameC(@class)}Wrapper"; Write(1, "EXPORT ", WriteTo.Header); Write($"{wrapperClassName}* {wrapperClassName}_new(", WriteTo.Header | WriteTo.Source); WriteLine(ListToLines(methodCallbacks, WriteTo.Header, 1) + ");", WriteTo.Header); WriteLine(ListToLines(methodCallbacks, WriteTo.Source) + ")", WriteTo.Source); WriteLine('{', WriteTo.Source); Write(1, $"return new {wrapperClassName}(", WriteTo.Source); WriteLine( ListToLines(virtualMethods.Select(m => $"{m.Name}Callback"), WriteTo.Source, 1) + ");", WriteTo.Source); WriteLine('}', WriteTo.Source); _hasCppClassSeparatingWhitespace = false; hasSourceWhiteSpace = false; }
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; }
public ClassDefinition(string name, HeaderDefinition header = null, ClassDefinition parent = null) { Name = name; Header = header; Parent = parent; }
protected virtual bool IsExcludedClass(ClassDefinition cl) { return(false); }
private void WriteClass(ClassDefinition c) { foreach (var child in c.Classes) { WriteClass(child); } if (!ClassNeedsExtensions(c)) { return; } _extensionMethods.Clear(); EnsureWhiteSpace(WriteTo.CS); WriteTabs(1, WriteTo.CS); csWriter.WriteLine("[EditorBrowsable(EditorBrowsableState.Never)]"); WriteTabs(1, WriteTo.CS); csWriter.WriteLine("public static class {0}Extensions", c.ManagedName); WriteTabs(1, WriteTo.CS); csWriter.WriteLine('{'); foreach (var prop in c.Properties) { if (_extensionClassesInternal.ContainsKey(prop.Type.ManagedName)) { // Getter with out parameter bufferBuilder.Clear(); WriteTabs(2, WriteTo.Buffer); WriteLine(string.Format("public unsafe static void Get{0}(this {1} obj, out {2} value)", prop.Name, c.ManagedName, _extensionClassesExternal[prop.Type.ManagedName]), WriteTo.Buffer); WriteTabs(2, WriteTo.Buffer); WriteLine('{', WriteTo.Buffer); WriteTabs(3, WriteTo.Buffer); WriteLine(string.Format("fixed ({0}* valuePtr = &value)", _extensionClassesExternal[prop.Type.ManagedName]), WriteTo.Buffer); WriteTabs(3, WriteTo.Buffer); WriteLine('{', WriteTo.Buffer); WriteTabs(4, WriteTo.Buffer); Write("*(", WriteTo.Buffer); Write(_extensionClassesInternal[prop.Type.ManagedName], WriteTo.Buffer); WriteLine(string.Format("*({0}*)valuePtr = obj.{1};", _extensionClassesInternal[prop.Type.ManagedName], prop.Name), WriteTo.Buffer); WriteTabs(3, WriteTo.Buffer); WriteLine('}', WriteTo.Buffer); WriteTabs(2, WriteTo.Buffer); WriteLine('}', WriteTo.Buffer); _extensionMethods.Add(new KeyValuePair<string, string>("Get" + prop.Name, bufferBuilder.ToString())); // Getter with return value bufferBuilder.Clear(); WriteTabs(2, WriteTo.Buffer); WriteLine(string.Format("public static {0} Get{1}(this {1} obj)", _extensionClassesExternal[prop.Type.ManagedName], prop.Name, c.ManagedName), WriteTo.Buffer); WriteTabs(2, WriteTo.Buffer); WriteLine('{', WriteTo.Buffer); WriteTabs(3, WriteTo.Buffer); WriteLine(string.Format("{0} value;", _extensionClassesExternal[prop.Type.ManagedName]), WriteTo.Buffer); WriteTabs(3, WriteTo.Buffer); WriteLine(string.Format("Get{0}(obj, out value)", prop.Name), WriteTo.Buffer); WriteTabs(3, WriteTo.Buffer); WriteLine("return value;", WriteTo.Buffer); WriteTabs(2, WriteTo.Buffer); WriteLine('}', WriteTo.Buffer); _extensionMethods.Add(new KeyValuePair<string, string>("Get" + prop.Name, bufferBuilder.ToString())); if (prop.Setter == null) { continue; } // Setter with ref parameter bufferBuilder.Clear(); WriteTabs(2, WriteTo.Buffer); WriteLine(string.Format("public unsafe static void Set{0}(this {1} obj, ref {2} value)", prop.Name, c.ManagedName, _extensionClassesExternal[prop.Type.ManagedName]), WriteTo.Buffer); WriteTabs(2, WriteTo.Buffer); WriteLine('{', WriteTo.Buffer); WriteTabs(3, WriteTo.Buffer); WriteLine(string.Format("fixed ({0}* valuePtr = &value)", _extensionClassesExternal[prop.Type.ManagedName]), WriteTo.Buffer); WriteTabs(3, WriteTo.Buffer); WriteLine('{', WriteTo.Buffer); WriteTabs(4, WriteTo.Buffer); WriteLine(string.Format("obj.{0} = *({1}*)valuePtr;", prop.Name, _extensionClassesInternal[prop.Type.ManagedName]), WriteTo.Buffer); WriteTabs(3, WriteTo.Buffer); WriteLine('}', WriteTo.Buffer); WriteTabs(2, WriteTo.Buffer); WriteLine('}', WriteTo.Buffer); _extensionMethods.Add(new KeyValuePair<string, string>("Set" + prop.Name, bufferBuilder.ToString())); // Setter with non-ref parameter bufferBuilder.Clear(); WriteTabs(2, WriteTo.Buffer); WriteLine(string.Format("public static void Set{0}(this {1} obj, {2} value)", prop.Name, c.ManagedName, _extensionClassesExternal[prop.Type.ManagedName]), WriteTo.Buffer); WriteTabs(2, WriteTo.Buffer); WriteLine('{', WriteTo.Buffer); WriteTabs(3, WriteTo.Buffer); WriteLine(string.Format("Set{0}(obj, ref value);", prop.Name), WriteTo.Buffer); WriteTabs(2, WriteTo.Buffer); WriteLine('}', WriteTo.Buffer); _extensionMethods.Add(new KeyValuePair<string, string>("Set" + prop.Name, bufferBuilder.ToString())); } } foreach (var method in c.Methods) { if (!MethodNeedsExtensions(method)) { continue; } WriteMethod(method); } foreach (var method in _extensionMethods.OrderBy(key => key.Key)) { EnsureWhiteSpace(WriteTo.CS); csWriter.Write(method.Value); hasCSWhiteSpace = false; } WriteTabs(1, WriteTo.CS); csWriter.WriteLine('}'); hasCSWhiteSpace = false; }
void ParseClassCursor(Cursor cursor) { string className = cursor.Spelling; string fullyQualifiedName = TypeRefDefinition.GetFullyQualifiedName(cursor); ClassDefinition @class; if (project.ClassDefinitions.TryGetValue(fullyQualifiedName, out @class)) { if (@class.IsParsed) { return; } @class.Parent = _context.Class; } else { switch (cursor.Kind) { case CursorKind.ClassTemplate: @class = new ClassTemplateDefinition(className, _context.Header, _context.Class); break; case CursorKind.EnumDecl: @class = new EnumDefinition(className, _context.Header, _context.Class); break; default: @class = new ClassDefinition(className, _context.Header, _context.Class); break; } @class.NamespaceName = _context.Namespace; if (@class.FullyQualifiedName != fullyQualifiedName) { Console.WriteLine("Parsing error at " + fullyQualifiedName); } project.ClassDefinitions[fullyQualifiedName] = @class; } _context.Class = @class; _context.Class.IsParsed = true; // Unnamed struct escapes to the surrounding scope if (!(string.IsNullOrEmpty(className) && cursor.Kind == CursorKind.StructDecl)) { if (_context.Class.Parent != null) { _context.Class.Parent.NestedClasses.Add(_context.Class); } else { _context.Header.Classes.Add(_context.Class); } } AccessSpecifier parentMemberAccess = _context.MemberAccess; // Default class/struct access specifier switch (cursor.Kind) { case CursorKind.ClassDecl: _context.MemberAccess = AccessSpecifier.Private; break; case CursorKind.StructDecl: _context.Class.IsStruct = true; _context.MemberAccess = AccessSpecifier.Public; break; case CursorKind.ClassTemplate: if (cursor.TemplateCursorKind != CursorKind.ClassDecl) { _context.MemberAccess = AccessSpecifier.Private; } else { _context.MemberAccess = AccessSpecifier.Public; } break; case CursorKind.TypedefDecl: var underlying = cursor.TypedefDeclUnderlyingType.Canonical; if (underlying.TypeKind == ClangSharp.Type.Kind.Pointer && underlying.Pointee.TypeKind == ClangSharp.Type.Kind.FunctionProto) { _context.Class.IsFunctionProto = true; } break; } if (cursor.Kind == CursorKind.EnumDecl) { var @enum = _context.Class as EnumDefinition; foreach (var constantDecl in cursor.Children .Where(c => c.Kind == CursorKind.EnumConstantDecl)) { string valueSpelling = ""; var value = constantDecl.Children.FirstOrDefault(); if (value != null) { var valueTokens = _context.TranslationUnit.Tokenize(value.Extent) .Where(t => t.Kind != TokenKind.Comment && !t.Spelling.Equals(",") && !t.Spelling.Equals("}")); valueSpelling = string.Join("", valueTokens.Select(t => t.Spelling)); } @enum.EnumConstants.Add(new EnumConstant(constantDecl.Spelling, valueSpelling)); } } else { cursor.VisitChildren(ClassVisitor); if (_context.Class.BaseClass == null) { // Clang doesn't give the base class if it's a template, // tokenize the class definition and extract the base template if it exists var tokens = _context.TranslationUnit.Tokenize(cursor.Extent) .TakeWhile(t => !t.Spelling.Equals("{")) .SkipWhile(t => !t.Spelling.Equals(":")); if (tokens.Any()) { var baseTokens = tokens.ToList(); int templSpecStart = -1, templSpecEnd = -1; for (int i = 0; i < baseTokens.Count; i++) { var token = baseTokens[i]; if (token.Spelling == "<") { templSpecStart = i; } else if (token.Spelling == ">") { templSpecEnd = i; } } if (templSpecStart != -1 && templSpecEnd != -1) { string template = baseTokens[templSpecStart - 1].Spelling; string templateSpec = string.Join(" ", baseTokens.GetRange(templSpecStart + 1, templSpecEnd - templSpecStart - 1) .Select(t => t.Spelling)); string templateName = $"{template}<{templateSpec}>"; ClassDefinition classTemplate; if (!project.ClassDefinitions.TryGetValue(templateName, out classTemplate)) { var classTemplateNew = new ClassTemplateDefinition(template, _context.Header); classTemplateNew.TemplateParameters.Add(templateSpec); var baseTemplate = project.ClassDefinitions.FirstOrDefault(c => c.Value.Name.Equals(template)); classTemplateNew.BaseClass = baseTemplate.Value; project.ClassDefinitions[templateName] = classTemplateNew; classTemplate = classTemplateNew; } _context.Class.BaseClass = classTemplate; } } } } // Restore parent state _context.Class = _context.Class.Parent; _context.MemberAccess = parentMemberAccess; }
void FindForwardReferences(List<ClassDefinition> forwardRefs, ClassDefinition c) { foreach (PropertyDefinition prop in c.Properties) { AddForwardReference(forwardRefs, prop.Type, c.Header); } foreach (MethodDefinition method in c.Methods) { if (method.IsConstructor && c.HidePublicConstructors) { continue; } AddForwardReference(forwardRefs, method.ReturnType, c.Header); foreach (ParameterDefinition param in method.Parameters) { AddForwardReference(forwardRefs, param.Type, c.Header); } } foreach (ClassDefinition cl in c.Classes) { FindForwardReferences(forwardRefs, cl); } }
private static bool RequiresMathNamespace(ClassDefinition @class) { if (@class.Classes.Any(RequiresMathNamespace)) return true; if (@class.IsExcluded) return false; foreach (var method in @class.Methods.Where(m => !m.IsExcluded)) { if (@class.HidePublicConstructors && method.IsConstructor) continue; if (_mathClasses.Contains(method.ReturnType.ManagedName)) return true; if (method.Parameters.Any(param => _mathClasses.Contains(param.Type.ManagedName))) { return true; } } return false; }
void OutputClass(ClassDefinition @class, int level) { EnsureHeaderWhiteSpace(); EnsureSourceWhiteSpace(); // Write access modifier WriteTabs(level); if (level == 1) { HeaderWrite("public "); } // Write class definition HeaderWrite($"ref class {@class.ManagedName}"); if (@class.IsAbstract) { HeaderWrite(" abstract"); } else if (@class.IsStaticClass) { HeaderWrite(" sealed"); } if (@class.BaseClass != null) { HeaderWriteLine($" : {@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](IsExcludedClass)) { 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($"{@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 && !m.IsExcluded)) { EnsureSourceWhiteSpace(); SourceWriteLine($"#define Native static_cast<{@class.FullyQualifiedName}*>(_native)"); 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($"{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($"{@class.FullNameCppCli}::"); Write($"{@class.ManagedName}({@class.FullyQualifiedName}* native)"); HeaderWriteLine(';'); SourceWriteLine(); if (@class.BaseClass != null) { WriteTabs(1, true); SourceWriteLine($": {@class.BaseClass.ManagedName}(native)"); } 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.1: "The access-specifier of a destructor in a ref class is ignored." WriteTabs(level + 1); HeaderWriteLine($"~{@class.ManagedName}();"); // ECMA-372 19.13.2: "The access-specifier of a finalizer in a ref class is ignored." WriteTabs(level + 1); HeaderWriteLine($"!{@class.ManagedName}();"); hasHeaderWhiteSpace = false; EnsureSourceWhiteSpace(); SourceWriteLine($"{@class.FullNameCppCli}::~{@class.ManagedName}()"); SourceWriteLine('{'); SourceWriteLine($"\tthis->!{@class.ManagedName}();"); SourceWriteLine('}'); SourceWriteLine(); SourceWriteLine($"{@class.FullNameCppCli}::!{@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); } } } } // Write non-constructor methods var methods = @class.Methods.Where(m => !m.IsConstructor && !m.IsExcluded); 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($"#ifndef {typeConditional}"); hasSourceWhiteSpace = true; } else { EnsureHeaderWhiteSpace(); } EnsureAccess(level, ref currentAccess, RefAccessSpecifier.Public); WriteTabs(level + 1); HeaderWriteLine($"property {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; }
// Accepts a ClassDefinition for recursion void WriteEnumClass(ClassDefinition @class, int level) { var @enum = @class as EnumDefinition; if (@enum == null) { foreach (var childClass in @class.Classes) { WriteEnumClass(childClass, level); } return; } EnsureWhiteSpace(WriteTo.CS); if (@enum.IsFlags) { WriteTabs(level, WriteTo.CS); WriteLine("[Flags]", WriteTo.CS); } WriteTabs(level, WriteTo.CS); WriteLine($"public enum {@enum.ManagedName}", WriteTo.CS); WriteTabs(level, WriteTo.CS); WriteLine('{', WriteTo.CS); for (int i = 0; i < @enum.EnumConstants.Count; i++) { WriteTabs(level + 1, WriteTo.CS); if (@enum.EnumConstantValues[i].Equals("")) { Write(@enum.EnumConstants[i], WriteTo.CS); } else { Write($"{@enum.EnumConstants[i]} = {@enum.EnumConstantValues[i]}", WriteTo.CS); } if (i < @enum.EnumConstants.Count - 1) { Write(',', WriteTo.CS); } WriteLine(WriteTo.CS); } WriteTabs(level, WriteTo.CS); WriteLine('}', WriteTo.CS); hasCSWhiteSpace = false; }
private static bool RequiresInterop(ClassDefinition @class) { if (@class.Methods.Any(m => !m.IsConstructor && !m.IsExcluded)) return true; if ([email protected] && @class.BaseClass == null) return true; if ([email protected] && [email protected]) return true; return false; }
void WriteClass(ClassDefinition c, int level) { if (c.IsExcluded || c.IsTypedef || c.IsPureEnum || c is ClassTemplateDefinition || c is EnumDefinition) { return; } if (wrapperHeaderGuards.ContainsKey(c.Name)) { WriteClassWrapper(c); } // Write class definition EnsureWhiteSpace(WriteTo.CS); WriteTabs(level, WriteTo.CS); Write("public ", WriteTo.CS); if (c.IsAbstract) { Write("abstract ", WriteTo.CS); } Write($"class {c.ManagedName}", WriteTo.CS); if (c.BaseClass != null) { Write(" : ", WriteTo.CS); WriteLine(c.BaseClass.FullNameCppCli.Replace("::", "."), WriteTo.CS); } else if (c.IsStaticClass) { WriteLine(WriteTo.CS); } else { WriteLine(" : IDisposable", WriteTo.CS); } WriteTabs(level, WriteTo.CS); WriteLine("{", WriteTo.CS); hasCSWhiteSpace = true; // Write child classes foreach (var cl in c.Classes.OrderBy(x => x.FullNameCppCli)) { WriteClass(cl, level + 1); } // Write the native pointer to the base class if (c.BaseClass == null && !c.IsStaticClass) { EnsureWhiteSpace(WriteTo.CS); WriteTabs(level + 1, WriteTo.CS); WriteLine("internal IntPtr _native;", WriteTo.CS); if (c.HasPreventDelete) { WriteTabs(level + 1, WriteTo.CS); WriteLine("bool _preventDelete;", WriteTo.CS); hasCSWhiteSpace = false; } hasCSWhiteSpace = false; } // Write cached property fields if (c.CachedProperties.Any()) { EnsureWhiteSpace(WriteTo.CS); foreach (var cachedProperty in c.CachedProperties.OrderBy(p => p.Key)) { WriteTabs(level + 1, WriteTo.CS); string name = cachedProperty.Key; name = char.ToLower(name[0]) + name.Substring(1); WriteLine(string.Format("{0} {1} _{2};", cachedProperty.Value.Access.ToString().ToLower(), cachedProperty.Value.Property.Type.ManagedNameCS, name), WriteTo.CS); } hasCSWhiteSpace = false; } // Write methods bufferBuilder.Clear(); // Write constructors if (!c.IsStaticClass) { // Write C# internal constructor if (!c.NoInternalConstructor) { EnsureWhiteSpace(WriteTo.CS); WriteTabs(level + 1, WriteTo.CS); Write($"internal {c.ManagedName}(IntPtr native", WriteTo.CS); if (c.HasPreventDelete) { Write(", bool preventDelete", WriteTo.CS); } WriteLine(')', WriteTo.CS); if (c.BaseClass != null) { WriteTabs(level + 2, WriteTo.CS); Write(": base(native", WriteTo.CS); if (c.HasPreventDelete) { if (!c.BaseClass.HasPreventDelete) { // Base class should also have preventDelete //throw new NotImplementedException(); } Write(", preventDelete", WriteTo.CS); } else { if (c.BaseClass.HasPreventDelete) { Write(", true", WriteTo.CS); } } WriteLine(')', WriteTo.CS); } WriteTabs(level + 1, WriteTo.CS); WriteLine('{', WriteTo.CS); if (c.BaseClass == null) { WriteTabs(level + 2, WriteTo.CS); WriteLine("_native = native;", WriteTo.CS); if (c.HasPreventDelete) { WriteTabs(level + 2, WriteTo.CS); WriteLine("_preventDelete = preventDelete;", WriteTo.CS); } } WriteTabs(level + 1, WriteTo.CS); WriteLine('}', WriteTo.CS); hasCSWhiteSpace = false; } // Write public constructors if (!c.HidePublicConstructors && !c.IsAbstract) { int overloadIndex = 0; var constructors = c.Methods.Where(m => m.IsConstructor && !m.IsExcluded); if (constructors.Any()) { foreach (var constructor in constructors) { WriteMethod(constructor, level, ref overloadIndex); } } } } // Write methods var methods = c.Methods.Where(m => !m.IsConstructor && !m.IsExcluded).OrderBy(m => m.Name); var methodsOverloads = methods.GroupBy(m => m.Name); foreach (var groupByName in methodsOverloads) { int overloadIndex = 0; foreach (var method in groupByName) { WriteMethod(method, level, ref overloadIndex); } } // Write properties foreach (var prop in c.Properties) { WriteProperty(prop, level); } // Write delete method if (c.BaseClass == null && !c.IsStaticClass) { int overloadIndex = 0; var del = new MethodDefinition("delete", c, 0); del.ReturnType = new TypeRefDefinition(); WriteMethod(del, level, ref overloadIndex); c.Methods.Remove(del); } // Write DllImport clauses if (bufferBuilder.Length != 0) { EnsureWhiteSpace(WriteTo.CS); Write(bufferBuilder.ToString(), WriteTo.CS); } WriteTabs(level, WriteTo.CS); WriteLine("}", WriteTo.CS); hasCSWhiteSpace = false; hasCppClassSeparatingWhitespace = false; }
protected bool IsExcludedClass(ClassDefinition @class) { return @class is ClassTemplateDefinition || @class is EnumDefinition || @class.IsPureEnum || @class.IsExcluded || @class.IsFunctionProto; }
public void WriteClassWrapperDefinition(ClassDefinition cl) { List<MethodDefinition> baseAbstractMethods; List<MethodDefinition> thisAbstractMethods = cl.Methods.Where(x => x.IsVirtual).ToList(); List<MethodDefinition> abstractMethods = thisAbstractMethods.ToList(); if (cl.BaseClass != null) { baseAbstractMethods = cl.BaseClass.Target.Methods.Where(x => x.IsVirtual).ToList(); abstractMethods.AddRange(baseAbstractMethods); } else { baseAbstractMethods = new List<MethodDefinition>(); } EnsureWhiteSpace(WriteTo.Source); // Wrapper C++ Constructor Write(string.Format("{0}Wrapper::{0}Wrapper(", cl.Name), WriteTo.Source); int numMethods = abstractMethods.Count; for (int i = 0; i < numMethods; i++) { var method = abstractMethods[i]; string className = baseAbstractMethods.Contains(method) ? cl.BaseClass.ManagedName : cl.ManagedName; Write(string.Format("p{0}_{1} {2}Callback", className, method.ManagedName, method.Name), WriteTo.Source); if (i != numMethods - 1) { Write(", ", WriteTo.Source); } } WriteLine(')', WriteTo.Source); WriteLine('{', WriteTo.Source); foreach (MethodDefinition method in abstractMethods) { WriteLine(string.Format("\t_{0}Callback = {0}Callback;", method.Name), WriteTo.Source); } WriteLine('}', WriteTo.Source); WriteLine(WriteTo.Source); // Wrapper C++ methods foreach (MethodDefinition method in abstractMethods) { Write(string.Format("{0} {1}Wrapper::{2}(", method.ReturnType.Name, cl.Name, method.Name), WriteTo.Source); int numParameters = method.Parameters.Length; for (int i = 0; i < numParameters; i++) { var param = method.Parameters[i]; WriteType(param.Type, WriteTo.Source); Write(" ", WriteTo.Source); Write(param.Name, WriteTo.Source); if (i != numParameters - 1) { Write(", ", WriteTo.Source); } } WriteLine(')', WriteTo.Source); WriteLine('{', WriteTo.Source); Write("\t", WriteTo.Source); if (!method.IsVoid) { Write("return ", WriteTo.Source); } Write(string.Format("_{0}Callback(", method.Name), WriteTo.Source); for (int i = 0; i < numParameters; i++) { var param = method.Parameters[i]; Write(param.Name, WriteTo.Source); if (i != numParameters - 1) { Write(", ", WriteTo.Source); } } WriteLine(");", WriteTo.Source); WriteLine('}', WriteTo.Source); WriteLine(WriteTo.Source); } WriteLine(WriteTo.Source); }
protected static string GetFullNameC(ClassDefinition @class) { string className; ClassTemplateDefinition template = @class as ClassTemplateDefinition; if (template != null) { className = @class.Name + string.Join("_", template.TemplateParameters); } else { className = @class.Name; } if (@class.Parent != null) { return $"{GetFullNameC(@class.Parent)}_{@class.Name}"; } if (@class.NamespaceName != "") { return $"{@class.NamespaceName}_{@class.Name}"; } return @class.Name; }
public void WriteClassWrapperMethodPointers(ClassDefinition cl) { List<MethodDefinition> baseAbstractMethods; List<MethodDefinition> thisAbstractMethods = cl.Methods.Where(x => x.IsVirtual).ToList(); List<MethodDefinition> abstractMethods = thisAbstractMethods.ToList(); if (cl.BaseClass != null) { baseAbstractMethods = cl.BaseClass.Target.Methods.Where(x => x.IsVirtual).ToList(); abstractMethods.AddRange(baseAbstractMethods); } else { baseAbstractMethods = new List<MethodDefinition>(); } foreach (MethodDefinition method in thisAbstractMethods) { WriteLine(string.Format("#define p{0}_{1} void*", cl.ManagedName, method.ManagedName), WriteTo.Header); } }
void WriteClass(ClassDefinition @class, int level) { if (_wrapperHeaderGuards.ContainsKey(@class.Name)) { WriteWrapperClassConstructor(@class); } // Write child classes foreach (var c in @class.NestedClasses .Where(c => !IsExcludedClass(c)) .OrderBy(c => c.Name)) { WriteClass(c, level + 1); } // Group methods into constructors, destructors and methods var methodGroups = @class.Methods.GroupBy(m => { if (m.IsExcluded) return (CursorKind)0; if (m.IsConstructor) return CursorKind.Constructor; if (m.IsDestructor) return CursorKind.Destructor; return CursorKind.CxxMethod; }).ToDictionary(g => g.Key); // Constructors if ([email protected] && [email protected] && [email protected]) { IGrouping<CursorKind, MethodDefinition> constructors; if (methodGroups.TryGetValue(CursorKind.Constructor, out constructors)) { int overloadIndex = 0; foreach (var constructor in methodGroups[CursorKind.Constructor]) { WriteMethod(constructor, level, ref overloadIndex); } } } // Methods IGrouping<CursorKind, MethodDefinition> methods; if (methodGroups.TryGetValue(CursorKind.CxxMethod, out methods)) { foreach (var groupByName in methods.GroupBy(m => m.Name)) { int overloadIndex = 0; foreach (var method in groupByName) { WriteMethod(method, level, ref overloadIndex); } } } // Destructors IGrouping<CursorKind, MethodDefinition> destructors; if (methodGroups.TryGetValue(CursorKind.Destructor, out destructors)) { int overloadIndex = 0; foreach (var method in destructors) { WriteMethod(method, level, ref overloadIndex); } } _hasCppClassSeparatingWhitespace = false; }
private static bool RequiresMathNamespace(ClassDefinition cl) { if (cl.Classes.Any(RequiresMathNamespace)) { return true; } foreach (var method in cl.Methods) { if (method.ReturnType.ManagedName.Equals("Quaternion") || method.ReturnType.ManagedName.Equals("Transform") || method.ReturnType.ManagedName.Equals("Vector3")) { return true; } foreach (var param in method.Parameters) { if (param.Type.ManagedName.Equals("Quaternion") || param.Type.ManagedName.Equals("Transform") || param.Type.ManagedName.Equals("Vector3")) { return true; } } } return false; }
public void WriteWrapperClass(ClassDefinition @class) { List<MethodDefinition> baseVirtualMethods; var thisVirtualMethods = @class.Methods.Where(x => x.IsVirtual).ToList(); var virtualMethods = thisVirtualMethods.ToList(); if (@class.BaseClass != null) { baseVirtualMethods = @class.BaseClass.Methods.Where(x => x.IsVirtual).ToList(); virtualMethods.AddRange(baseVirtualMethods); } else { baseVirtualMethods = new List<MethodDefinition>(); } var methodCallbacks = virtualMethods.Select(m => { string className = baseVirtualMethods.Contains(m) ? GetFullNameC(@class.BaseClass) : GetFullNameC(@class); return $"p_{className}_{m.Name} {m.Name}Callback"; }).ToList(); if (!_hasCppClassSeparatingWhitespace) { WriteLine(); _hasCppClassSeparatingWhitespace = true; } // TODO: string headerGuard = wrapperHeaderGuards[@class.Name]; string parameters; if (thisVirtualMethods.Count != 0) { foreach (var method in thisVirtualMethods) { string methodPtr = $"p_{GetFullNameC(@class)}_{method.Name}"; Write($"typedef {method.ReturnType.Name} (*{methodPtr})(", WriteTo.Header); parameters = ListToLines(method.Parameters .Select(p => $"{GetTypeNameC(p.Type)} {p.Name}"), WriteTo.Header); WriteLine($"{parameters});", WriteTo.Header); } WriteLine(); } // Wrapper class string wrapperClassName = $"{GetFullNameC(@class)}Wrapper"; WriteLine($"class {wrapperClassName} : public {GetFullNameC(@class)}"); WriteLine("{"); WriteLine("private:"); foreach (var m in virtualMethods) { string className = baseVirtualMethods.Contains(m) ? GetFullNameC(@class.BaseClass) : GetFullNameC(@class); WriteLine(1, $"p_{className}_{m.Name} _{m.Name}Callback;"); } WriteLine(); WriteLine("public:"); // Wrapper constructor Write(1, $"{wrapperClassName}("); string constructorParams = ListToLines(methodCallbacks, WriteTo.Header, 1); WriteLine($"{constructorParams});"); WriteLine(); // Wrapper methods foreach (var m in virtualMethods) { Write(1, $"virtual {m.ReturnType.Name} {m.Name}("); string methodParams = ListToLines( m.Parameters.Select(p => $"{GetTypeNameC(p.Type)} {p.Name}"), WriteTo.Header, 1); WriteLine(methodParams + ");"); } WriteLine("};"); _hasCppClassSeparatingWhitespace = false; var prevTo = To; To = WriteTo.Source; EnsureWhiteSpace(); // Wrapper C++ Constructor Write($"{wrapperClassName}::{wrapperClassName}("); parameters = ListToLines(methodCallbacks, WriteTo.Source); WriteLine($"{parameters})"); WriteLine('{'); foreach (var method in virtualMethods) { WriteLine(1, string.Format("_{0}Callback = {0}Callback;", method.Name)); } WriteLine('}'); WriteLine(); // Wrapper C++ methods foreach (var method in virtualMethods) { Write($"{method.ReturnType.Name} {wrapperClassName}::{method.Name}("); parameters = ListToLines(method.Parameters .Select(p => $"{GetTypeNameC(p.Type)} {p.Name}"), WriteTo.Source); WriteLine($"{parameters})"); WriteLine('{'); WriteTabs(1); if (!method.IsVoid) { Write("return "); } Write($"_{method.Name}Callback("); parameters = ListToLines(method.Parameters .Select(p => p.Name), WriteTo.Source, 1); WriteLine($"{parameters});"); WriteLine('}'); WriteLine(); } WriteLine(); To = prevTo; }
void ParseClassCursor(Cursor cursor) { string className = cursor.Spelling; string fullyQualifiedName = TypeRefDefinition.GetFullyQualifiedName(cursor); ClassDefinition @class; if (project.ClassDefinitions.TryGetValue(fullyQualifiedName, out @class)) { if (@class.IsParsed) return; @class.Parent = _context.Class; } else { switch(cursor.Kind) { case CursorKind.ClassTemplate: @class = new ClassTemplateDefinition(className, _context.Header, _context.Class); break; case CursorKind.EnumDecl: @class = new EnumDefinition(className, _context.Header, _context.Class); break; default: @class = new ClassDefinition(className, _context.Header, _context.Class); break; } @class.NamespaceName = _context.Namespace; if (@class.FullyQualifiedName != fullyQualifiedName) { Console.WriteLine("Parsing error at " + fullyQualifiedName); } project.ClassDefinitions[fullyQualifiedName] = @class; } _context.Class = @class; _context.Class.IsParsed = true; // Unnamed struct escapes to the surrounding scope if (!(string.IsNullOrEmpty(className) && cursor.Kind == CursorKind.StructDecl)) { if (_context.Class.Parent != null) { _context.Class.Parent.NestedClasses.Add(_context.Class); } else { _context.Header.Classes.Add(_context.Class); } } AccessSpecifier parentMemberAccess = _context.MemberAccess; // Default class/struct access specifier switch (cursor.Kind) { case CursorKind.ClassDecl: _context.MemberAccess = AccessSpecifier.Private; break; case CursorKind.StructDecl: _context.Class.IsStruct = true; _context.MemberAccess = AccessSpecifier.Public; break; case CursorKind.ClassTemplate: if (cursor.TemplateCursorKind != CursorKind.ClassDecl) { _context.MemberAccess = AccessSpecifier.Private; } else { _context.MemberAccess = AccessSpecifier.Public; } break; case CursorKind.TypedefDecl: var underlying = cursor.TypedefDeclUnderlyingType.Canonical; if (underlying.TypeKind == ClangSharp.Type.Kind.Pointer && underlying.Pointee.TypeKind == ClangSharp.Type.Kind.FunctionProto) { _context.Class.IsFunctionProto = true; } break; } if (cursor.Kind == CursorKind.EnumDecl) { var @enum = _context.Class as EnumDefinition; foreach (var constantDecl in cursor.Children .Where(c => c.Kind == CursorKind.EnumConstantDecl)) { string valueSpelling = ""; var value = constantDecl.Children.FirstOrDefault(); if (value != null) { var valueTokens = _context.TranslationUnit.Tokenize(value.Extent) .Where(t => t.Kind != TokenKind.Comment && !t.Spelling.Equals(",") && !t.Spelling.Equals("}")); valueSpelling = string.Join("", valueTokens.Select(t => t.Spelling)); } @enum.EnumConstants.Add(new EnumConstant(constantDecl.Spelling, valueSpelling)); } } else { cursor.VisitChildren(ClassVisitor); if (_context.Class.BaseClass == null) { // Clang doesn't give the base class if it's a template, // tokenize the class definition and extract the base template if it exists ParseTemplateBaseCursor(cursor); } } // Restore parent state _context.Class = _context.Class.Parent; _context.MemberAccess = parentMemberAccess; }
bool IsExcludedClass(ClassDefinition c) { return(c.IsTypedef || c.IsPureEnum || c.IsExcluded); }