diff --git a/src/generator/Class.cs b/src/generator/Class.cs new file mode 100644 index 00000000..1c8dc358 --- /dev/null +++ b/src/generator/Class.cs @@ -0,0 +1,111 @@ +// +// Class.cs: Represents a C++ class +// +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Linq; +using System.CodeDom; +using System.CodeDom.Compiler; + +class Class +{ + public Class (Node n) { + Node = n; + Methods = new List (); + Fields = new List (); + } + + public Node Node { + get; set; + } + + public string Name { + get { + return Node.Name; + } + } + + public List Methods { + get; set; + } + + public List Fields { + get; set; + } + + public CodeTypeDeclaration GenerateClass (Generator g, CodeTypeDeclaration libDecl) { + var decl = new CodeTypeDeclaration (Name); + decl.IsPartial = true; + // FIXME: Inheritance + decl.BaseTypes.Add (new CodeTypeReference ("ICppObject")); + + var layout = new CodeTypeDeclaration ("_" + Name); + layout.IsStruct = true; + layout.TypeAttributes = TypeAttributes.NotPublic; + decl.Members.Add (layout); + + foreach (var f in Fields) { + CodeMemberField field = new CodeMemberField { Name = f.Name, Type = g.CppTypeToCodeDomType (f.Type) }; + layout.Members.Add (field); + } + + var iface = new CodeTypeDeclaration ("I" + Name); + iface.IsInterface = true; + layout.TypeAttributes = TypeAttributes.NotPublic; + iface.BaseTypes.Add (new CodeTypeReference ("ICppClassOverridable", new CodeTypeReference [] { new CodeTypeReference (decl.Name) })); + decl.Members.Add (iface); + + var layoutField = new CodeMemberField (new CodeTypeReference (typeof (Type)), "native_layout"); + layoutField.Attributes = MemberAttributes.Private|MemberAttributes.Static; + layoutField.InitExpression = new CodeTypeOfExpression (layout.Name); + decl.Members.Add (layoutField); + + var implField = new CodeMemberField (new CodeTypeReference (iface.Name), "impl"); + implField.Attributes = MemberAttributes.Private|MemberAttributes.Static; + var getclass = new CodeMethodReferenceExpression (new CodeFieldReferenceExpression (new CodeTypeReferenceExpression (libDecl.Name), "Test"), "GetClass", new CodeTypeReference [] { new CodeTypeReference (iface.Name), new CodeTypeReference (layout.Name), new CodeTypeReference (decl.Name) }); + implField.InitExpression = new CodeMethodInvokeExpression (getclass, new CodeExpression [] { new CodePrimitiveExpression (Name) }); + decl.Members.Add (implField); + //private static IClass impl = global::CppTests.Libs.Test.GetClass ("Class"); + + var ptrField = new CodeMemberField (new CodeTypeReference ("CppInstancePtr"), "native_ptr"); + ptrField.Attributes = MemberAttributes.Family; + decl.Members.Add (ptrField); + + var allocCtor = new CodeConstructor () { + }; + allocCtor.Parameters.Add (new CodeParameterDeclarationExpression (new CodeTypeReference ("CppLibrary"), "dummy")); + allocCtor.Statements.Add (new CodeAssignStatement (new CodeFieldReferenceExpression (null, "native_ptr"), new CodeMethodInvokeExpression (new CodeMethodReferenceExpression (new CodeFieldReferenceExpression (null, "impl"), "Alloc"), new CodeExpression [] { new CodeThisReferenceExpression () }))); + decl.Members.Add (allocCtor); + + var subclassCtor = new CodeConstructor () { + }; + subclassCtor.Parameters.Add (new CodeParameterDeclarationExpression (new CodeTypeReference ("CppTypeInfo"), "subClass")); + subclassCtor.Statements.Add (new CodeExpressionStatement (new CodeMethodInvokeExpression (new CodeMethodReferenceExpression (new CodeArgumentReferenceExpression ("subClass"), "AddBase"), new CodeExpression [] { new CodeFieldReferenceExpression (new CodeFieldReferenceExpression (null, "impl"), "TypeInfo") }))); + decl.Members.Add (subclassCtor); + + var nativeProperty = new CodeMemberProperty () { + Name = "Native", + Type = new CodeTypeReference ("CppInstancePtr"), + Attributes = MemberAttributes.Public|MemberAttributes.Final + }; + nativeProperty.GetStatements.Add (new CodeMethodReturnStatement (new CodeFieldReferenceExpression (new CodeThisReferenceExpression (), "native_ptr"))); + decl.Members.Add (nativeProperty); + + var disposeMethod = new CodeMemberMethod () { + Name = "Dispose", + Attributes = MemberAttributes.Public + }; + if (Methods.Any (m => m.IsDestructor)) + disposeMethod.Statements.Add (new CodeExpressionStatement (new CodeMethodInvokeExpression (new CodeMethodReferenceExpression (new CodeFieldReferenceExpression (null, "impl"), "Destruct"), new CodeExpression [] { new CodeFieldReferenceExpression (null, "Native") }))); + disposeMethod.Statements.Add (new CodeExpressionStatement (new CodeMethodInvokeExpression (new CodeMethodReferenceExpression (new CodeFieldReferenceExpression (null, "Native"), "Dispose")))); + decl.Members.Add (disposeMethod); + + foreach (Method m in Methods) { + iface.Members.Add (m.GenerateIFaceMethod (g)); + decl.Members.Add (m.GenerateWrapperMethod (g)); + } + + return decl; + } +} diff --git a/src/generator/Field.cs b/src/generator/Field.cs new file mode 100644 index 00000000..0d255ae9 --- /dev/null +++ b/src/generator/Field.cs @@ -0,0 +1,26 @@ +// +// Field.cs: Represents a field of a C++ class +// + +using System; +using System.Collections.Generic; +using System.CodeDom; +using System.CodeDom.Compiler; + +using Mono.VisualC.Interop; + +class Field +{ + public Field (string name, CppType type) { + Name = name; + Type = type; + } + + public string Name { + get; set; + } + + public CppType Type { + get; set; + } +} diff --git a/src/generator/Generator.cs b/src/generator/Generator.cs new file mode 100644 index 00000000..55a13eed --- /dev/null +++ b/src/generator/Generator.cs @@ -0,0 +1,389 @@ +// +// Generator.cs: C++ Interop Code Generator +// +// + +using System; +using System.IO; +using System.Collections.Generic; +using System.Xml; +using System.Linq; +using System.Reflection; +using System.CodeDom; +using System.CodeDom.Compiler; +using Microsoft.CSharp; + +using NDesk.Options; + +using Mono.VisualC.Interop; + +public class Generator +{ + // Command line arguments + string OutputDir; + string Namespace; + string LibBaseName; + string InputFileName; + string FilterFile; + + CodeDomProvider Provider; + CodeGeneratorOptions CodeGenOptions; + + // Classes to generate code for + Dictionary Filters; + + public static int Main (String[] args) { + var generator = new Generator (); + generator.Run (args); + return 0; + } + + int ParseArguments (String[] args) { + bool help = false; + + var p = new OptionSet { + { "h|?|help", "Show this help message", v => help = v != null }, + { "o=", "Set the output directory", v => OutputDir = v }, + { "ns=|namespace=", "Set the namespace of the generated code", v => Namespace = v }, + { "lib=", "The base name of the C++ library, i.e. 'qt' for libqt.so", v =>LibBaseName = v }, + { "filters=", "A file containing filter directives for filtering classes", v => FilterFile = v } + }; + + try { + args = p.Parse (args).ToArray (); + } catch (OptionException) { + Console.WriteLine ("Try `generator --help' for more information."); + return 1; + } + + if (help) { + p.WriteOptionDescriptions (Console.Error); + return 1; + } + + if (args.Length != 1) { + Console.WriteLine ("Usage: generator "); + return 1; + } + + InputFileName = args [0]; + + if (LibBaseName == null) { + Console.WriteLine ("The --lib= option is required."); + return 1; + } + + if (OutputDir == null) + OutputDir = "output"; + + return 0; + } + + void Run (String[] args) { + if (ParseArguments (args) != 0) { + Environment.Exit (1); + } + + Node root = LoadXml (InputFileName); + + if (FilterFile != null) + LoadFilters (FilterFile); + + CreateClasses (root); + + CreateMethods (); + + GenerateCode (); + } + + Node LoadXml (string file) { + XmlReader reader = XmlReader.Create (file, new XmlReaderSettings ()); + + Node[] parents = new Node [1024]; + + Node root = null; + + while (reader.Read()) { + if (reader.IsStartElement ()) { + string type = reader.Name; + + var attributes = new Dictionary (); + while (reader.MoveToNextAttribute ()) { + attributes [reader.Name] = reader.Value; + } + + Node n = new Node { + Id = "", + Type = type, + Attributes = attributes, + Children = new List () + }; + + if (attributes.ContainsKey ("id")) { + n.Id = attributes ["id"]; + Node.IdToNode [n.Id] = n; + } + + if (attributes.ContainsKey ("name")) + n.Name = attributes ["name"]; + + if (parents [reader.Depth - 1] != null) { + //Console.WriteLine (parents [reader.Depth - 1].type + " -> " + e.type); + parents [reader.Depth - 1].Children.Add (n); + } + parents [reader.Depth] = n; + + if (n.Type == "GCC_XML" && root == null) + root = n; + } + } + + return root; + } + + void LoadFilters (string file) { + Filters = new Dictionary (); + foreach (string s in File.ReadAllLines (file)) { + Filters [s] = s; + } + } + + List Classes; + Dictionary NodeToClass; + + void CreateClasses (Node root) { + List classNodes = root.Children.Where (o => o.Type == "Class" || o.Type == "Struct").ToList (); + classNodes.RemoveAll (o => o.IsTrue ("incomplete") || !o.HasValue ("name")); + + if (Filters != null) + classNodes.RemoveAll (o => !Filters.ContainsKey (o.Name)); + + List classes = new List (); + NodeToClass = new Dictionary (); + + foreach (Node n in classNodes) { + Console.WriteLine (n.Name); + + Class klass = new Class (n); + classes.Add (klass); + NodeToClass [n] = klass; + } + + // Compute bases + foreach (Class klass in classes) { + foreach (Node bn in klass.Node.Children.Where (o => o.Type == "Base")) { + //Class baseClass = nodeToClass [bn.NodeForAttr ("type")]; + throw new NotImplementedException (); + } + } + + Classes = classes; + } + + void CreateMethods () { + foreach (Class klass in Classes) { + if (!klass.Node.HasValue ("members")) + continue; + + int fieldCount = 0; + foreach (string id in klass.Node ["members"].Split (' ')) { + if (id == "") + continue; + Node n = Node.IdToNode [id]; + + bool ctor = false; + bool dtor = false; + + switch (n.Type) { + case "Field": + CppType fieldType = GetType (GetTypeNode (n)); + string fieldName; + if (n.Name != "") + fieldName = n.Name; + else + fieldName = "field" + fieldCount++; + klass.Fields.Add (new Field (fieldName, fieldType)); + break; + case "Constructor": + ctor = true; + break; + case "Destructor": + dtor = true; + break; + case "Method": + break; + default: + continue; + } + + if (!n.CheckValue ("access", "public") || (n.HasValue ("overrides") && !dtor)) + continue; + + if (!n.IsTrue ("extern") && !n.IsTrue ("inline")) + continue; + + // FIXME: Casing + string name = dtor ? "Destruct" : n.Name; + + var method = new Method (n) { + Name = name, + IsVirtual = n.IsTrue ("virtual"), + IsStatic = n.IsTrue ("static"), + IsConst = n.IsTrue ("const"), + IsInline = n.IsTrue ("inline"), + IsArtificial = n.IsTrue ("artificial"), + IsConstructor = ctor, + IsDestructor = dtor + }; + + CppType retType; + if (n.HasValue ("returns")) + retType = GetType (n.NodeForAttr ("returns")); + else + retType = CppTypes.Void; + if (retType.ElementType == CppTypes.Unknown) + throw new NotImplementedException (); + + method.ReturnType = retType; + + bool skip = false; + int c = 0; + List argTypes = new List (); + foreach (Node arg in n.Children.Where (o => o.Type == "Argument")) { + string argname; + if (arg.Name == null || arg.Name == "") + argname = "arg" + c; + else + argname = arg.Name; + + CppType argtype = GetType (GetTypeNode (arg)); + if (argtype.ElementType == CppTypes.Unknown) { + //Console.WriteLine ("Skipping method " + klass.Name + "::" + member.Name + " () because it has an argument with unknown type '" + TypeNodeToString (arg) + "'."); + skip = true; + } + + method.Parameters.Add (new Tuple (argname, argtype)); + argTypes.Add (argtype); + + c++; + } + if (skip) + continue; + + // FIXME: More complete type name check + if (ctor && argTypes.Count == 1 && argTypes [0].ElementType == CppTypes.Class && argTypes [0].ElementTypeName == klass.Name && argTypes [0].Modifiers.Count == 2 && argTypes [0].Modifiers.Contains (CppModifiers.Const) && argTypes [0].Modifiers.Contains (CppModifiers.Reference)) + method.IsCopyCtor = true; + + Console.WriteLine ("\t" + klass.Name + "." + method.Name); + + klass.Methods.Add (method); + } + } + } + + // Return a CppType for the type node N, return CppTypes.Unknown for unknown types + CppType GetType (Node n) { + return GetType (n, new CppType ()); + } + + CppType GetType (Node n, CppType modifiers) { + switch (n.Type) { + case "ArrayType": + return GetType (GetTypeNode (n), modifiers.Modify (CppModifiers.Array)); + case "PointerType": + return GetType (GetTypeNode (n), modifiers.Modify (CppModifiers.Pointer)); + case "ReferenceType": + return GetType (GetTypeNode (n), modifiers.Modify (CppModifiers.Reference)); + case "FundamentalType": + return modifiers.CopyTypeFrom (new CppType (n.Name)); + case "CvQualifiedType": + if (n.IsTrue ("const")) + return GetType (GetTypeNode (n), modifiers.Modify (CppModifiers.Const)); + else + throw new NotImplementedException (); + case "Class": + // FIXME: Missing classes + return modifiers.CopyTypeFrom (new CppType (CppTypes.Class, NodeToClass [n].Name)); + default: + throw new NotImplementedException (n.Type); + } + } + + Node GetTypeNode (Node n) { + return Node.IdToNode [n.Attributes ["type"]]; + } + + public CodeTypeReference CppTypeToCodeDomType (CppType t) { + CodeTypeReference rtype = null; + // FIXME: Modifiers + switch (t.ElementType) { + case CppTypes.Void: + break; + case CppTypes.Bool: + rtype = new CodeTypeReference (typeof (bool)); + break; + case CppTypes.Int: + rtype = new CodeTypeReference (typeof (int)); + break; + case CppTypes.Class: + // FIXME: Full name + rtype = new CodeTypeReference (t.ElementTypeName); + break; + default: + throw new NotImplementedException (t.ToString ()); + } + return rtype; + } + + void GenerateCode () { + Directory.CreateDirectory (OutputDir); + + Provider = new CSharpCodeProvider (); + CodeGenOptions = new CodeGeneratorOptions { BlankLinesBetweenMembers = false }; + + CodeTypeDeclaration libDecl = null; + + // Generate Libs class + { + var cu = new CodeCompileUnit (); + var ns = new CodeNamespace (Namespace); + ns.Imports.Add(new CodeNamespaceImport("System")); + ns.Imports.Add(new CodeNamespaceImport("Mono.VisualC.Interop")); + cu.Namespaces.Add (ns); + + var decl = new CodeTypeDeclaration ("Libs"); + + var field = new CodeMemberField (new CodeTypeReference ("CppLibrary"), "Test"); + field.Attributes = MemberAttributes.Public|MemberAttributes.Static; + field.InitExpression = new CodeObjectCreateExpression (new CodeTypeReference ("CppLibrary"), new CodeExpression [] { new CodePrimitiveExpression ("Test") }); + decl.Members.Add (field); + + ns.Types.Add (decl); + + libDecl = decl; + + //Provider.GenerateCodeFromCompileUnit(cu, Console.Out, CodeGenOptions); + using (TextWriter w = File.CreateText (Path.Combine (OutputDir, "Libs.cs"))) { + Provider.GenerateCodeFromCompileUnit(cu, w, CodeGenOptions); + } + } + + // Generate user classes + foreach (Class klass in Classes) { + var cu = new CodeCompileUnit (); + var ns = new CodeNamespace (Namespace); + ns.Imports.Add(new CodeNamespaceImport("System")); + ns.Imports.Add(new CodeNamespaceImport("Mono.VisualC.Interop")); + cu.Namespaces.Add (ns); + + ns.Types.Add (klass.GenerateClass (this, libDecl)); + + //Provider.GenerateCodeFromCompileUnit(cu, Console.Out, CodeGenOptions); + using (TextWriter w = File.CreateText (Path.Combine (OutputDir, klass.Name + ".cs"))) { + // These are reported for the fields of the native layout structures + Provider.GenerateCodeFromCompileUnit (new CodeSnippetCompileUnit("#pragma warning disable 0414, 0169"), w, CodeGenOptions); + Provider.GenerateCodeFromCompileUnit(cu, w, CodeGenOptions); + } + } + } +} diff --git a/src/generator/Main.cs b/src/generator/Main.cs deleted file mode 100644 index 18c6b510..00000000 --- a/src/generator/Main.cs +++ /dev/null @@ -1,893 +0,0 @@ -using System; -using NDesk.Options; -using System.IO; -using System.Text; -using System.Text.RegularExpressions; -using System.Xml; -using System.Xml.XPath; -using System.Xml.Linq; -using System.Collections.Generic; -using System.Linq; - -using Mono.VisualC.Interop; -using Mono.VisualC.Interop.ABI; -using Mono.VisualC.Interop.Util; -using Mono.VisualC.Code; -using Mono.VisualC.Code.Atoms; - -using System.Reflection; -using System.CodeDom; -using System.CodeDom.Compiler; -using Microsoft.CSharp; - -namespace Mono.VisualC.Tools.Generator { - public class Generator { - public static readonly string [] genericTypeArgs = new string [] { "T", "U", "V", "W", "X", "Y", "Z" }; - - public string Source { get; set; } - public string Dir { get; set; } - public bool AbiTest { get; set; } - public bool Validation { get; set; } - public string Library { get; set; } - - private string nspace; - public string Namespace { - get { return nspace; } - set { - nspace = value; - Tree.ManagedNamespace = value; - //enumerations.ManagedNamespace = value; - //unions.ManagedNamespace = value; - } - } - - public Dictionary Classes; - public HashSet UnknownTypes; - - public CodeDomProvider Provider { get; set; } - public CodeGeneratorOptions Options { get; set; } - - private CodeUnit Tree { get; set; } - //private CodeUnit currentUnit; - //private CodeUnit enumerations; - //private CodeUnit unions; - private Dictionary properties; - - private int enumCount = 0; - private int unionCount = 0; - - private HashSet fileList; - - public static void Main (string [] args) - { - bool help = false; - Generator gen = new Generator (); - gen.Validation = true; - var p = new OptionSet { { "h|?|help", "Show this help message", v => help = v != null }, { "f=", "Set the xml outputted by gccxml to parse", v => gen.Source = v }, { "o=", "Set the output directory", v => gen.Dir = v }, { "ns=", "Set the namespace", v => gen.Namespace = v }, { "lib=", "Additional reference libraries", v => gen.Library = v }, { "lang=", "Language of the outputted library (C#, VB, etc)", v => gen.Provider = CodeDomProvider.CreateProvider (v) }, { "testabi", "Test the Itanium name mangling abi against the bindings", v => gen.AbiTest = v != null }, { "n", "Don't validate", v => gen.Validation = !(v != null) } }; - - List extra = null; - try { - extra = p.Parse (args); - } catch (OptionException) { - Console.WriteLine ("Try `generator --help' for more information."); - return; - } - - if (help) { - p.WriteOptionDescriptions (Console.Error); - return; - } - - if (gen.Source == null) { - Console.Error.WriteLine ("-f required"); - return; - } - - if (gen.Dir == null) - gen.Dir = "output"; - Directory.CreateDirectory (gen.Dir); - - if (gen.Namespace == null) - gen.Namespace = "Wrappers"; - - if (gen.Library == null) - gen.Library = "Lib"; - if (gen.Library.EndsWith (".dll") || gen.Library.EndsWith (".so") || gen.Library.EndsWith (".dylib")) - gen.Library = gen.Library.Substring (0, gen.Library.LastIndexOf ('.')); - - if (gen.Provider == null) - gen.Provider = new CSharpCodeProvider (); - - gen.Options = new CodeGeneratorOptions { BlankLinesBetweenMembers = false }; - - gen.Run (); - } - - public Generator () - { - Classes = new Dictionary (); - UnknownTypes = new HashSet (); - - Tree = new CodeUnit { ManagedNamespace = Namespace }; - //enumerations = new CodeUnit { ManagedNamespace = Namespace }; - //unions = new CodeUnit { ManagedNamespace = Namespace }; - properties = new Dictionary (); - - fileList = new HashSet (); - } - - public void Run () - { - Console.WriteLine ("Generating bindings..."); - - Console.WriteLine ("\tLoading XML"); - XmlDocument xmldoc = new XmlDocument (); - xmldoc.Load (Source); - - Console.WriteLine ("\tPreprocessing"); - List entries = Preprocess (xmldoc); - - Console.WriteLine ("\tPreprocessing Classes"); - List removed = PreprocessClasses (entries); - - Console.WriteLine ("\tProcessing Classes"); - ProcessClasses (entries, removed); - - // save files - Console.WriteLine ("\tSaving Classes"); - Save (); - - Console.WriteLine ("\tGenerating Static lib"); - GenerateStaticLibField (); - - Console.WriteLine ("Generating unknown types"); - GenerateUnknownTypeStubs (); - - - if (Validation) { - Console.WriteLine ("Validating bindings..."); - Assembly asm = Validate (); - - if (asm != null && AbiTest) { - Console.WriteLine ("Testing Itanium ABI name mangling against bindings..."); - TestAbi (asm); - } - } - //File.Delete (fileList.Where (f => f.StartsWith ("UnknownTypes")).Single ()); - - } - - - - public void Save () - { - //if (enumerations.Atoms.Any ()) - // SaveFile (enumerations.WrapperToCodeDom (Provider), "Enums"); - //if (unions.Atoms.Any ()) - // SaveFile (unions.WrapperToCodeDom (Provider), "Unions"); - - SaveFile (Tree.WrapperToCodeDom (Provider), "FlatFile"); - } - - - /***************************************************************************/ - - - List Preprocess (XmlDocument xmldoc) - { - XmlNode node = xmldoc.SelectSingleNode ("/GCC_XML"); - Entry.typelist = new Dictionary> (); - Entry.idlist = new Dictionary (); - return Preprocess (node); - } - - int typecount = 0; - List Preprocess (XmlNode parent) - { - List data = new List (); - foreach (XmlNode node in parent.ChildNodes) { - Dictionary entry = new Dictionary (); - foreach (XmlAttribute att in node.Attributes) { - entry[att.Name] = att.Value; - } - - Entry e = new Entry { id = "", type = node.Name, name = "", reftype = "", attributes = entry }; - - if (entry.ContainsKey ("name")) - e.id = e.name = entry["name"]; - - if (entry.ContainsKey ("id")) - e.id = entry["id"]; - - if (entry.ContainsKey ("type")) - e.reftype = entry["type"]; - - if (node.HasChildNodes) - e.children = Preprocess (node); - else - e.children = new List (); - - if (!Entry.typelist.ContainsKey (e.type)) - Entry.typelist[e.type] = new Dictionary (); - - if (entry.ContainsKey ("id")) - Entry.idlist.Add (e.id, e); - - string id = e.id; - int count = 0; - while (Entry.typelist[e.type].ContainsKey (id)) { - id = e.id + "|" + count++; - } - Entry.typelist[e.type].Add (id, e); - data.Add (e); - } - return data; - } - - List PreprocessClasses (List entries) - { - List filter = new List() { - "QItemSelection" - }; - - - List removed = new List (entries.Where (o => (o.type == "Class" || o.type == "Struct") && (o.IsTrue ("incomplete") || !o.HasValue ("name") || (Entry.idlist[o["file"]].name.StartsWith ("/"))))); - removed.AddRange (entries.Where (o => filter.Contains (o.name)).ToList ()); - entries.RemoveAll (o => (o.type == "Class" || o.type == "Struct") && (o.IsTrue ("incomplete") || !o.HasValue ("name") || (Entry.idlist[o["file"]].name.StartsWith ("/")))); - entries.RemoveAll (o => filter.Contains (o.name)); - - - foreach (Entry clas in entries.Where (o => o.type == "Class" || o.type == "Struct")) { - clas.computedName = clas.name; - - string ns = GetNamespace (clas); - CppType currentType = new CppType (clas.type.ToLower (), ns != null ? ns + "::" + clas.computedName : clas.computedName); - - // FIXME: better way to do this (GCC-XML output doesn't seem to leave much choice) - var templated = currentType.Modifiers.OfType ().SingleOrDefault (); - if (templated != null) { - clas.isTemplate = true; - string baseName = currentType.ElementTypeName; - string computedName = clas.computedName; - clas.computedName = baseName; - - clas.atom = new Class (clas.computedName) { - StaticCppLibrary = string.Format ("{0}.Libs.{1}", Namespace, Library), - OriginalType = currentType - }; - - int i = 0; - foreach (var t in templated.Types) - clas.Class.TemplateArguments.Add (genericTypeArgs[i++]); - - clas.Class.GenericName = String.Format ("{0}<{1}>", baseName, string.Join (",", clas.Class.TemplateArguments.ToArray ())); - Console.Error.WriteLine ("Warning: Creating generic type {0}<{1}> from the instantiated template {2} (very buggy!!!)", - baseName, - string.Join (",", clas.Class.TemplateArguments.ToArray ()), computedName); - } else { - clas.atom = new Class (clas.computedName) { - StaticCppLibrary = string.Format ("{0}.Libs.{1}", Namespace, Library), - OriginalType = currentType - }; - } - - // FIXME: Handle when base class name is fully qualified - foreach (Entry bs in clas.children.Where (o => o.type == "Base")) { - clas.Class.Bases.Add (new Class.BaseClass { Name = bs.Base.Class != null ? (bs.Base.Class.GenericName ?? bs.Base.Class.Name) : bs.computedName, Access = bs.CheckValue ("access", "public") ? Access.Public : bs.CheckValue ("access", "protected") ? Access.Protected : Access.Private, IsVirtual = bs.IsTrue ("virtual") }); - } - - IEnumerable nested = null; - if (IsCreated (clas.Class.OriginalType, true, out nested)) - continue; - - GetContainer (clas, Tree).Atoms.AddLast (clas.atom); - if (nested != null) { - foreach (var orphan in nested) - clas.Class.Atoms.AddLast (orphan); - } - } - - return removed; - } - - void ProcessClasses (List entries, List removed) - { - foreach (Entry clas in entries.Where (o => o.type == "Class" || o.type == "Struct")) { - - var templated = clas.Class.OriginalType.Modifiers.OfType ().SingleOrDefault (); - Dictionary methods = new Dictionary (); - - foreach (Entry member in clas.Members) { - bool ctor = false; - bool dtor = false; - int fieldCount = 0; - - switch (member.type) { - case "Constructor": - ctor = true; - break; - case "Destructor": - dtor = true; - break; - case "Method": - break; - case "Field": - CppType fieldType = findType (clas.Class, member.Base, removed); - string fieldName = "field" + fieldCount++; - if (member.name != "") - fieldName = member.name; - clas.Class.Atoms.AddLast (new Field (fieldName, fieldType)); - continue; - default: - continue; - } - - // Now we're processing a method... - - if (!member.CheckValue ("access", "public") || (member.HasValue ("overrides") && !dtor) || !member.IsTrue ("extern")) - continue; - - string mname = member.name; - - CppType retType = member.HasValue ("returns") ? findType (clas.Class, Entry.idlist[member["returns"]], removed) : CppTypes.Void; - - if (templated != null) { - for (int i = 0; i < templated.Types.Length; i++) - retType = replaceType (retType, templated.Types[i], genericTypeArgs[i]); - } - - var methodAtom = new Method (dtor ? "Destruct" : mname) { - RetType = retType, - IsVirtual = member.IsTrue ("virtual"), - IsStatic = member.IsTrue ("static"), - IsConst = member.IsTrue ("const"), - IsConstructor = ctor, - IsDestructor = dtor, - Klass = clas.Class - }; - - if (AbiTest) - methodAtom.Mangled = new NameTypePair { Name = member.attributes["mangled"], Type = typeof(ItaniumAbi) }; - - List argTypes = new List (); - int c = 0; - foreach (Entry arg in member.children.Where (o => o.type == "Argument")) { - string argname; - if (arg.name == "") - argname = "arg" + c; - else - argname = arg.name; - - CppType argtype = findType (clas.Class, arg.Base, removed); - if (templated != null) { - for (int i = 0; i < templated.Types.Length; i++) - argtype = replaceType (argtype, templated.Types[i], genericTypeArgs[i]); - } - - methodAtom.Parameters.Add (new NameTypePair { Name = argname, Type = argtype }); - argTypes.Add (argtype); - - // tee hee - c++; - } - - - // Try to filter out duplicate methods - MethodSignature sig = new MethodSignature (methodAtom.FormattedName, argTypes); - string conflictingSig; - if (methods.TryGetValue (sig, out conflictingSig)) { - // FIXME: add comment to explain why it's commented out - string demangled = member.attributes["demangled"]; - //Console.Error.WriteLine ("Warning: Method \"{0}\" in class {1} omitted because it conflicts with \"{2}\"", demangled, name, conflictingSig); - methodAtom.Comment = string.Format ("FIXME:Method \"{0}\" omitted because it conflicts with \"{1}\"", demangled, conflictingSig); - methodAtom.CommentedOut = true; - } else - methods.Add (sig, member.attributes["demangled"]); - - // Record unknown types in parameters and return type - IsCreated (methodAtom.RetType); - foreach (var arg in methodAtom.Parameters) - IsCreated (arg.Type); - - // Detect if this is a property... - - // if it's const, returns a value, has no parameters, and there is no other method with the same name - // in this class assume it's a property getter (for now?) - if (methodAtom.IsConst && !retType.Equals (CppTypes.Void) && !methodAtom.Parameters.Any () && - clas.Members.Where (o => o.name == mname).FirstOrDefault () == null) { - var pname = methodAtom.FormattedName; - Property propertyAtom; - - if (properties.TryGetValue (pname, out propertyAtom)) { - propertyAtom.Getter = methodAtom; - } else { - propertyAtom = new Property (pname) { Getter = methodAtom }; - properties.Add (pname, propertyAtom); - clas.Class.Atoms.AddLast (propertyAtom); - } - - continue; - } - - // if it's name starts with "set", does not return a value, and has one arg (besides this ptr) - // and there is no other method with the same name... - if (mname.ToLower ().StartsWith ("set") && retType.Equals (CppTypes.Void) && - methodAtom.Parameters.Count == 1 && clas.Members.Where (o => o.name == mname).FirstOrDefault () == null) { - - string getterName = mname.Substring (3).TrimStart ('_').ToLower (); - - string pname = methodAtom.FormattedName.Substring (3); - Property propertyAtom = null; - - // ...AND there is a corresponding getter method that returns the right type, then assume it's a property setter - bool doIt = false; - if (properties.TryGetValue (pname, out propertyAtom)) { - doIt = propertyAtom.Getter != null && propertyAtom.Getter.RetType.Equals (methodAtom.Parameters[0].Type); - } else { - Entry getter = clas.Members.Where (o => o.name == getterName).FirstOrDefault (); - doIt = (getter != null && findType (clas.Class, Entry.idlist[getter.attributes["returns"]], removed).Equals (methodAtom.Parameters[0].Type)); - } - if (doIt) { - if (propertyAtom != null) { - propertyAtom.Setter = methodAtom; - } else { - propertyAtom = new Property (pname) { Setter = methodAtom }; - properties.Add (pname, propertyAtom); - clas.Class.Atoms.AddLast (propertyAtom); - } - - // set the method's arg name to "value" so that the prop setter works right - var valueParam = methodAtom.Parameters[0]; - valueParam.Name = "value"; - methodAtom.Parameters[0] = valueParam; - - continue; - } - } - clas.Class.Atoms.AddLast (methodAtom); - } - } - } - - Assembly Validate () - { - var compileParams = new CompilerParameters { GenerateInMemory = true, IncludeDebugInformation = true, WarningLevel = 0, TreatWarningsAsErrors = false }; - compileParams.ReferencedAssemblies.Add (typeof(CppLibrary).Assembly.Location); - - CompilerResults results = Provider.CompileAssemblyFromFile (compileParams, fileList.ToArray ()); - var errors = results.Errors.Cast ().Where (e => !e.IsWarning); - - int count = 0; - foreach (var error in errors) { - - if (count == 0) { - foreach (var fix in Postfixes.List) { - if (fix.TryFix (error.ErrorText, this)) - return Validate (); - } - } - - Console.Error.WriteLine ("{0}({1},{2}): error {3}: {4}", error.FileName, error.Line, error.Column, error.ErrorNumber, error.ErrorText); - count++; - } - if (count > 0) - Console.Error.WriteLine ("Validation failed with {0} compilation errors.", count); - else - Console.WriteLine ("Bindings compiled successfully."); - - - return results.CompiledAssembly; - } - - void TestAbi (Assembly assembly) - { - var classes = assembly.GetExportedTypes ().Select (t => new { Name = Regex.Replace (t.Name, "\\`.$", ""), Interface = t.GetNestedType ("I" + t.Name) }).Where (k => k.Interface != null); - var abi = new ItaniumAbi (); - - foreach (var klass in classes) { - bool klassSuccess = true; - - foreach (var method in klass.Interface.GetMethods ()) { - - var testAttribute = (AbiTestAttribute)method.GetCustomAttributes (typeof(AbiTestAttribute), false).FirstOrDefault (); - - string expected = testAttribute.MangledName; - string actual = abi.GetMangledMethodName (klass.Name, method); - - if (actual != expected) { - Console.Error.WriteLine ("Error: Expected \"{0}\" but got \"{1}\" when mangling method \"{2}\" in class \"{3}\"", expected, actual, method.ToString (), klass.Name); - klassSuccess = false; - } - } - - if (klassSuccess) - Console.WriteLine ("Successfully mangled all method names in class \"" + klass.Name + "\""); - } - - } - - string GetNamespace (Entry entry) - { - string nsname; - if (Entry.idlist[entry["context"]] == null) - return null; - - Entry ns = entry.Namespace; - if (ns.type == "Namespace") - nsname = ns.name; else if (ns.type == "Class" || ns.type == "Struct") - nsname = new CppType (ns.name).ElementTypeName; - else - throw new NotSupportedException ("Unknown context: " + ns.type); - - if (nsname == "::") - return null; - - string parent = GetNamespace (ns); - if (parent != null) - return parent + "::" + nsname; - - return nsname; - } - - CodeContainer GetContainer (Entry entry, CodeContainer def) - { - string nsname; - if (Entry.idlist[entry.attributes["context"]] == null) - return null; - - Entry ns = entry.Namespace; - - if (ns.type == "Namespace") - nsname = ns.name; else if (ns.type == "Class" || ns.type == "Struct") - nsname = new CppType (ns.name).ElementTypeName; - else - throw new NotSupportedException ("Unknown context: " + ns.type); - - if (nsname == "::") - return def; - CodeContainer parent = GetContainer (ns, def); - CodeContainer container = parent.Atoms.OfType ().Where (a => a.Name == nsname).SingleOrDefault (); - - if (container == null) { - container = new Namespace (nsname); - parent.Atoms.AddLast (container); - } - - return container; - } - - public CodeContainer GetPath (string [] pathNames) - { - return GetPath (Tree, pathNames, false); - } - - static CodeContainer GetPath (CodeContainer root, string [] pathNames, bool create) - { - foreach (var item in pathNames) { - CodeContainer prospect = root.Atoms.OfType ().Where (a => a.Name == item).SingleOrDefault (); - if (prospect == null) { - if (create) { - prospect = new Namespace (item); - root.Atoms.AddLast (prospect); - } else - return null; - } - - root = prospect; - } - - return root; - } - - CppType ProcessEnum (Entry entry) - { - string fullName = entry.name; - if (entry.name == "") { - fullName = "Enum" + enumCount++; - string ns = GetNamespace (entry); - if (ns != null) - fullName = ns + "::" + entry.name; - } - CppType enumType = new CppType (CppTypes.Enum, fullName); - - IEnumerable dontCare; - if (entry.name == "" || !IsCreated (enumType, true, out dontCare)) { - - Enumeration enumAtom = new Enumeration (fullName); - foreach (Entry m in entry.children.Where (o => o.type == "EnumValue")) { - enumAtom.Items.Add (new Enumeration.Item { Name = m.name, Value = Convert.ToInt32 (m.attributes["init"]) }); - } - - CodeContainer nested = GetContainer (entry, Tree); - //GetContainer (root, enm, currentUnit); - nested.Atoms.AddLast (enumAtom); - } - - return enumType; - } - - CppType ProcessUnion (Class clas, Entry entry, List removed) - { - string fullName = entry.name; - if (entry.name == "") { - fullName = "Union" + unionCount++; - string ns = GetNamespace (entry); - if (ns != null) - fullName = ns + "::" + entry.name; - } - - CppType unionType = new CppType (CppTypes.Union, fullName); - - IEnumerable orphans = null; - if (entry.name == "" || !IsCreated (unionType, true, out orphans)) { - Union unionAtom = new Union (fullName); - - foreach (Entry m in entry.Members.Where (o => o.type == "Field")) { - Field field = new Field (m.name, findType (clas, m.Base, removed)); - unionAtom.Atoms.AddLast (field); - } - - CodeContainer nested = GetContainer (entry, Tree); - //GetContainer (root, union, currentUnit); - nested.Atoms.AddLast (unionAtom); - - if (orphans != null) { - foreach (var orphan in orphans) - unionAtom.Atoms.AddLast (orphan); - } - } - return unionType; - } - - void GenerateStaticLibField () - { - string name = "Lib_" + Library; - if (File.Exists (Path.Combine (Dir, fname (name)))) - return; - - var ccu = new CodeCompileUnit (); - var ns = new CodeNamespace (Namespace); - var cls = new CodeTypeDeclaration ("Libs") { TypeAttributes = TypeAttributes.NotPublic | TypeAttributes.Sealed | TypeAttributes.Class, IsPartial = true, IsClass = true }; - var field = new CodeMemberField (typeof(CppLibrary), Library) { Attributes = MemberAttributes.Public | MemberAttributes.Static, InitExpression = new CodeObjectCreateExpression (typeof(CppLibrary), new CodePrimitiveExpression (Library)) }; - cls.Members.Add (field); - ns.Types.Add (cls); - ccu.Namespaces.Add (ns); - - SaveFile (ccu, name); - } - - void GenerateUnknownTypeStubs () - { - /* - var ccu = new CodeCompileUnit (); - var ns = new CodeNamespace (Namespace); - - foreach (var type in UnknownTypes) { - var ctd = type.Value as CodeTypeDeclaration; - var newNS = type.Value as CodeNamespace; - - if (ctd != null) - ns.Types.Add (ctd); - else - ccu.Namespaces.Add (newNS); - } - - ccu.Namespaces.Add (ns); - SaveFile (ccu, "UnknownTypes"); - */ - var ukt = UnknownTypes.ToArray (); - foreach (var unknownType in ukt) { - CodeContainer container = Tree; - CppType type = new CppType (unknownType); - IEnumerable orphans; - - if (IsCreated (type, true, out orphans)) - continue; - - if (type.Namespaces != null) - container = GetPath (Tree, type.Namespaces, true); - - var atom = new Class (type.ElementTypeName); - - int i = 0; - foreach (var param in type.Modifiers.OfType ()) { - if (param.Types != null) { - foreach (var t in param.Types) { - atom.TemplateArguments.Add (genericTypeArgs[i++]); - } - } else { - atom.TemplateArguments.Add (genericTypeArgs[i++]); - } - } - - if (orphans != null) { - foreach (var orphan in orphans) - atom.Atoms.AddLast (orphan); - } - - container.Atoms.AddLast (atom); - } - } - - void SaveFile (CodeCompileUnit ccu, string baseName) - { - string name = Path.Combine (Dir, fname (baseName)); - if (File.Exists (name) && fileList.Contains (name)) - File.Delete (name); - if (File.Exists (name) && !fileList.Contains (name)) { - int i = 1; - while (File.Exists (Path.Combine (Dir, fname (baseName + i)))) - i++; - name = Path.Combine (Dir, fname (baseName + i)); - } - Console.WriteLine ("Generating " + name); - - var sw = File.CreateText (name); - Provider.GenerateCodeFromCompileUnit (ccu, sw, Options); - sw.Flush (); - sw.Close (); - sw.Dispose (); - - if (!fileList.Contains (name)) - fileList.Add (name); - } - - static CppType replaceType (CppType inType, CppType toReplace, string tn) - { - // FIXME: The order of some modifiers is not significant.. is this a problem? - if ( /* inType.ElementType == toReplace.ElementType && */((inType.Namespaces != null && toReplace.Namespaces != null && inType.Namespaces.SequenceEqual (toReplace.Namespaces)) || inType.Namespaces == null && toReplace.Namespaces == null) && inType.ElementTypeName == toReplace.ElementTypeName && inType.Modifiers.StartsWith (toReplace.Modifiers)) - return new CppType (CppTypes.Typename, tn, inType.Modifiers.Skip (toReplace.Modifiers.Count).ToArray ()); - - foreach (var tempMod in inType.Modifiers.OfType ()) - for (int i = 0; i < tempMod.Types.Length; i++) - tempMod.Types[i] = replaceType (tempMod.Types[i], toReplace, tn); - - return inType; - } - - // returns true if the type was already created - bool IsCreated (CppType type) - { - IEnumerable dontCare; - return IsCreated (type, false, out dontCare); - } - bool IsCreated (CppType type, bool toBeCreated, out IEnumerable orphanedAtoms) - { - orphanedAtoms = null; - if (type.ElementTypeName == null || type.ElementTypeName == "" || type.ElementType == CppTypes.Typename) - return true; - - // check template parameters recursively - foreach (var paramType in type.Modifiers.OfType ().Where (t => t.Types != null).SelectMany (t => t.Types)) - IsCreated (paramType); - - bool typeFound = false; - type.ElementType = CppTypes.Unknown; - for (int i = 0; i < type.Modifiers.Count; i++) { - if (type.Modifiers[i] != CppModifiers.Template) - type.Modifiers.RemoveAt (i); - } - - string qualifiedName = type.ToString (); - bool alreadyUnknown = UnknownTypes.Contains (qualifiedName); - - CodeContainer place = Tree; - if (type.Namespaces != null) - place = GetPath (type.Namespaces); - - if (place != null) { - typeFound = place.Atoms.OfType ().Where (c => c.Name == type.ElementTypeName).Any () || place.Atoms.OfType ().Where (e => e.Name == type.ElementTypeName).Any () || place.Atoms.OfType ().Where (u => u.Name == type.ElementTypeName).Any (); - - var sameNamedNamespace = place.Atoms.OfType ().Where (ns => ns.Name == type.ElementTypeName).SingleOrDefault (); - if (sameNamedNamespace != null) { - orphanedAtoms = sameNamedNamespace.Atoms; - - // FIXME: This could potentially be very slow - Tree.Atoms.Remove (sameNamedNamespace); - //currentUnit.Atoms.Remove (sameNamedNamespace); - //enumerations.Atoms.Remove (sameNamedNamespace); - //unions.Atoms.Remove (sameNamedNamespace); - } - } - - if (!typeFound && !toBeCreated && !alreadyUnknown) { - /*CodeObject codeObject; - - var ctd = new CodeTypeDeclaration (type.ElementTypeName) { - TypeAttributes = TypeAttributes.Public, - IsClass = true - }; - - codeObject = ctd; - - if (type.Namespaces != null) { - var ns = new CodeNamespace (Namespace + "." + string.Join (".", type.Namespaces)); - ns.Types.Add (ctd); - codeObject = ns; - } - - var template = type.Modifiers.OfType ().SingleOrDefault (); - if (template != null) { - for (int i = 0; i < template.Types.Length; i++) - ctd.TypeParameters.Add (genericTypeArgs [i]); - } - */ - UnknownTypes.Add (qualifiedName); - } else if ((typeFound || toBeCreated) && alreadyUnknown) - UnknownTypes.Remove (qualifiedName); - - return typeFound; - } - - CppType findType (Class clas, Entry entry, List removed) - { - if (entry == null) - return CppTypes.Unknown; - return findType (clas, entry, removed, new CppType ()); - } - - CppType findType (Class clas, Entry entry, List removed, CppType modifiers) - { - if (entry == null) - return CppTypes.Unknown; - string name = entry.name == "" ? "unknown" : entry.name; - - switch (entry.type) { - case "ArrayType": - return findType (clas, entry.Base, removed, modifiers.Modify (CppModifiers.Array)); - case "PointerType": - return findType (clas, entry.Base, removed, modifiers.Modify (CppModifiers.Pointer)); - case "ReferenceType": - return findType (clas, entry.Base, removed, modifiers.Modify (CppModifiers.Reference)); - case "CvQualifiedType": - return findType (clas, entry.Base, removed, modifiers.Modify ((from c in entry.attributes - where c.Key == "const" && c.Value == "1" - select CppModifiers.Const).DefaultIfEmpty (CppModifiers.Volatile).First ())); - - case "Typedef": - return findType (clas, entry.Base, removed, modifiers); - - case "FundamentalType": - return modifiers.CopyTypeFrom (new CppType (name)); - case "Class": - if (removed.Contains (entry)) - return modifiers.CopyTypeFrom (CppTypes.Unknown); - if (entry.Class.GenericName != null) { - if (clas == entry.Class) { - return modifiers.CopyTypeFrom (new CppType (CppTypes.Class, entry.Class.GenericName)); - } else { - return modifiers.CopyTypeFrom (CppTypes.Unknown); - } - } else - return modifiers.CopyTypeFrom (new CppType (CppTypes.Class, name)); - case "Struct": - if (removed.Contains (entry)) - return modifiers.CopyTypeFrom (CppTypes.Unknown); - return modifiers.CopyTypeFrom (new CppType (CppTypes.Struct, name)); - case "Union": - if (removed.Contains (entry)) - return modifiers.CopyTypeFrom (CppTypes.Unknown); - return modifiers.CopyTypeFrom (ProcessUnion (clas, entry, removed)); - case "Enumeration": - if (removed.Contains (entry)) - return modifiers.CopyTypeFrom (CppTypes.Unknown); - return modifiers.CopyTypeFrom (ProcessEnum (entry)); - - // FIXME: support function pointers betters - case "FunctionType": - return modifiers.CopyTypeFrom (CppTypes.Void); - case "MethodType": - return modifiers.CopyTypeFrom (CppTypes.Void); - case "Constructor": - return CppTypes.Unknown; - } - - throw new NotImplementedException ("Unknown type node: " + entry.type); - } - - string fname (string name) - { - return name.Replace ("<", "_").Replace (">", "_").Replace (":", "_").Replace ("*", "_").Replace (",", "_").Replace (" ", "_") + "." + Provider.FileExtension; - } - } -} diff --git a/src/generator/Makefile.am b/src/generator/Makefile.am index a7dc75a2..621cd1e0 100644 --- a/src/generator/Makefile.am +++ b/src/generator/Makefile.am @@ -10,11 +10,9 @@ ASSEMBLY = bin/Debug/generator.exe ASSEMBLY_MDB = $(ASSEMBLY).mdb COMPILE_TARGET = exe PROJECT_REFERENCES = \ - ../Mono.VisualC.Code/bin/Debug/Mono.VisualC.Code.dll \ ../Mono.VisualC.Interop/bin/Debug/Mono.VisualC.Interop.dll BUILD_DIR = bin/Debug -MONO_VISUALC_CODE_DLL_SOURCE=../Mono.VisualC.Code/bin/Debug/Mono.VisualC.Code.dll MONO_VISUALC_INTEROP_DLL_SOURCE=../Mono.VisualC.Interop/bin/Debug/Mono.VisualC.Interop.dll MONO_VISUALC_INTEROP_DLL=$(BUILD_DIR)/Mono.VisualC.Interop.dll GENERATOR_EXE_MDB_SOURCE=bin/Debug/generator.exe.mdb @@ -30,11 +28,9 @@ ASSEMBLY = bin/Release/generator.exe ASSEMBLY_MDB = COMPILE_TARGET = exe PROJECT_REFERENCES = \ - ../Mono.VisualC.Code/bin/Release/Mono.VisualC.Code.dll \ ../Mono.VisualC.Interop/bin/Release/CPPInterop.dll BUILD_DIR = bin/Release -MONO_VISUALC_CODE_DLL_SOURCE=../Mono.VisualC.Code/bin/Release/Mono.VisualC.Code.dll MONO_VISUALC_INTEROP_DLL= GENERATOR_EXE_MDB= CPPINTEROP_DLL_SOURCE=../Mono.VisualC.Interop/bin/Release/CPPInterop.dll @@ -46,7 +42,6 @@ AL=al2 SATELLITE_ASSEMBLY_NAME=$(notdir $(basename $(ASSEMBLY))).resources.dll PROGRAMFILES = \ - $(MONO_VISUALC_CODE_DLL) \ $(MONO_VISUALC_INTEROP_DLL) \ $(GENERATOR_EXE_MDB) \ $(CPPINTEROP_DLL) @@ -56,15 +51,16 @@ BINARIES = \ RESGEN=resgen2 - + all: $(ASSEMBLY) $(PROGRAMFILES) $(BINARIES) FILES = \ - Main.cs \ - MethodSignature.cs \ + Generator.cs \ Options.cs \ - Postfixes.cs \ - Entry.cs + Node.cs \ + Class.cs \ + Method.cs \ + Field.cs DATA_FILES = @@ -85,10 +81,8 @@ CLEANFILES = $(PROGRAMFILES) $(BINARIES) include $(top_srcdir)/Makefile.include -MONO_VISUALC_CODE_DLL = $(BUILD_DIR)/Mono.VisualC.Code.dll GENERATOR = $(BUILD_DIR)/generator -$(eval $(call emit-deploy-target,MONO_VISUALC_CODE_DLL)) $(eval $(call emit-deploy-target,MONO_VISUALC_INTEROP_DLL)) $(eval $(call emit-deploy-wrapper,GENERATOR,generator,x)) $(eval $(call emit-deploy-target,CPPINTEROP_DLL)) diff --git a/src/generator/Method.cs b/src/generator/Method.cs new file mode 100644 index 00000000..eb00c597 --- /dev/null +++ b/src/generator/Method.cs @@ -0,0 +1,156 @@ +// +// Method.cs: Represents a C++ method +// + +using System; +using System.Collections.Generic; +using System.CodeDom; +using System.CodeDom.Compiler; + +using Mono.VisualC.Interop; + +class Method +{ + public Method (Node node) { + Node = node; + Parameters = new List> (); + } + + public Node Node { + get; set; + } + + public string Name { + get; set; + } + + public bool IsVirtual { + get; set; + } + + public bool IsStatic { + get; set; + } + + public bool IsConst { + get; set; + } + + public bool IsInline { + get; set; + } + + public bool IsArtificial { + get; set; + } + + public bool IsConstructor { + get; set; + } + + public bool IsDestructor { + get; set; + } + + public bool IsCopyCtor { + get; set; + } + + public CppType ReturnType { + get; set; + } + + public List> Parameters { + get; set; + } + + public CodeMemberMethod GenerateIFaceMethod (Generator g) { + var method = new CodeMemberMethod () { + Name = Name + }; + + if (!IsStatic) + method.Parameters.Add (new CodeParameterDeclarationExpression (new CodeTypeReference ("CppInstancePtr"), "this")); + + CodeTypeReference rtype = g.CppTypeToCodeDomType (ReturnType); + if (rtype != null) + method.ReturnType = rtype; + + foreach (var p in Parameters) { + CppType ptype = p.Item2; + var param = new CodeParameterDeclarationExpression (g.CppTypeToCodeDomType (ptype), p.Item1); + if (!IsVirtual && !ptype.ToString ().Equals (string.Empty)) + param.CustomAttributes.Add (new CodeAttributeDeclaration ("MangleAsAttribute", new CodeAttributeArgument (new CodePrimitiveExpression (ptype.ToString ())))); + // FIXME: Structs too + if (ptype.ElementType == CppTypes.Class && !ptype.Modifiers.Contains (CppModifiers.Reference) && !ptype.Modifiers.Contains (CppModifiers.Pointer)) + param.CustomAttributes.Add (new CodeAttributeDeclaration ("ByVal")); + method.Parameters.Add (param); + } + + // FIXME: Copy ctor + + if (IsVirtual) + method.CustomAttributes.Add (new CodeAttributeDeclaration ("Virtual")); + if (IsConstructor) + method.CustomAttributes.Add (new CodeAttributeDeclaration ("Constructor")); + if (IsDestructor) + method.CustomAttributes.Add (new CodeAttributeDeclaration ("Destructor")); + if (IsConst) + method.CustomAttributes.Add (new CodeAttributeDeclaration ("Const")); + if (IsInline) + method.CustomAttributes.Add (new CodeAttributeDeclaration ("Inline")); + if (IsArtificial) + method.CustomAttributes.Add (new CodeAttributeDeclaration ("Artificial")); + if (IsCopyCtor) + method.CustomAttributes.Add (new CodeAttributeDeclaration ("CopyConstructor")); + if (IsStatic) + method.CustomAttributes.Add (new CodeAttributeDeclaration ("Static")); + + return method; + } + + public CodeMemberMethod GenerateWrapperMethod (Generator g) { + CodeMemberMethod method; + + if (IsConstructor) + method = new CodeConstructor () { + Name = Name + }; + else + method = new CodeMemberMethod () { + Name = Name + }; + method.Attributes = MemberAttributes.Public; + if (IsStatic) + method.Attributes |= MemberAttributes.Static; + + CodeTypeReference rtype = g.CppTypeToCodeDomType (ReturnType); + if (rtype != null) + method.ReturnType = rtype; + + foreach (var p in Parameters) { + var param = new CodeParameterDeclarationExpression (g.CppTypeToCodeDomType (p.Item2), p.Item1); + method.Parameters.Add (param); + } + + if (IsConstructor) { + //this.native_ptr = impl.Alloc(this); + method.Statements.Add (new CodeAssignStatement (new CodeFieldReferenceExpression (null, "native_ptr"), new CodeMethodInvokeExpression (new CodeMethodReferenceExpression (new CodeFieldReferenceExpression (null, "impl"), "Alloc"), new CodeExpression [] { new CodeThisReferenceExpression () }))); + } + + // Call the iface method + CodeExpression[] args = new CodeExpression [Parameters.Count + (IsStatic ? 0 : 1)]; + if (!IsStatic) + args [0] = new CodeFieldReferenceExpression (null, "Native"); + for (int i = 0; i < Parameters.Count; ++i) + args [i + (IsStatic ? 0 : 1)] = new CodeArgumentReferenceExpression (Parameters [i].Item1); + var call = new CodeMethodInvokeExpression (new CodeMethodReferenceExpression (new CodeFieldReferenceExpression (null, "impl"), Name), args); + + if (rtype == null || IsConstructor) + method.Statements.Add (call); + else + method.Statements.Add (new CodeMethodReturnStatement (call)); + + return method; + } +} diff --git a/src/generator/Node.cs b/src/generator/Node.cs new file mode 100644 index 00000000..e83e2942 --- /dev/null +++ b/src/generator/Node.cs @@ -0,0 +1,64 @@ +// +// Node.cs: +// +// +using System; +using System.Collections.Generic; + + +// +// This class represents an XML node read from the output of gccxml +// +class Node { + + // The XML element type + public string Type { + get; set; + } + + // The value of the 'id' attribute + public string Id { + get; set; + } + + // The value of the 'name' attribute or null + public string Name { + get; set; + } + + // Attributes + public Dictionary Attributes { + get; set; + } + + // The children nodes of this node + public List Children { + get; set; + } + + public string this [string key] { + get { + return Attributes [key]; + } + } + + // Maps ids to nodes + public static Dictionary IdToNode = new Dictionary (); + + // For an attribute which contains an id, return the corresponding Node + public Node NodeForAttr (string attr) { + return IdToNode [Attributes [attr]]; + } + + public bool IsTrue (string key) { + return Attributes.ContainsKey (key) && Attributes[key] == "1"; + } + + public bool HasValue (string key) { + return Attributes.ContainsKey (key) && Attributes[key] != ""; + } + + public bool CheckValue (string key, string name) { + return Attributes.ContainsKey (key) && Attributes[key] == name; + } +}