Browse Source

Generator rewrite.

pull/1/head
Zoltan Varga 15 years ago committed by Andreia Gaita
parent
commit
344debf842
  1. 111
      src/generator/Class.cs
  2. 26
      src/generator/Field.cs
  3. 389
      src/generator/Generator.cs
  4. 893
      src/generator/Main.cs
  5. 16
      src/generator/Makefile.am
  6. 156
      src/generator/Method.cs
  7. 64
      src/generator/Node.cs

111
src/generator/Class.cs

@ -0,0 +1,111 @@ @@ -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<Method> ();
Fields = new List<Field> ();
}
public Node Node {
get; set;
}
public string Name {
get {
return Node.Name;
}
}
public List<Method> Methods {
get; set;
}
public List<Field> 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 <IClass, _Class, Class>("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;
}
}

26
src/generator/Field.cs

@ -0,0 +1,26 @@ @@ -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;
}
}

389
src/generator/Generator.cs

@ -0,0 +1,389 @@ @@ -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<string, string> 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 <options> <input xml file>");
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<string, string> ();
while (reader.MoveToNextAttribute ()) {
attributes [reader.Name] = reader.Value;
}
Node n = new Node {
Id = "",
Type = type,
Attributes = attributes,
Children = new List<Node> ()
};
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 <string, string> ();
foreach (string s in File.ReadAllLines (file)) {
Filters [s] = s;
}
}
List<Class> Classes;
Dictionary<Node, Class> NodeToClass;
void CreateClasses (Node root) {
List<Node> 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<Class> classes = new List<Class> ();
NodeToClass = new Dictionary <Node, Class> ();
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<CppType> argTypes = new List<CppType> ();
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<string, CppType> (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);
}
}
}
}

893
src/generator/Main.cs

@ -1,893 +0,0 @@ @@ -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<string, string> Classes;
public HashSet<string> 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<string, Property> properties;
private int enumCount = 0;
private int unionCount = 0;
private HashSet<string> 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<string> 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<string, string> ();
UnknownTypes = new HashSet<string> ();
Tree = new CodeUnit { ManagedNamespace = Namespace };
//enumerations = new CodeUnit { ManagedNamespace = Namespace };
//unions = new CodeUnit { ManagedNamespace = Namespace };
properties = new Dictionary<string, Property> ();
fileList = new HashSet<string> ();
}
public void Run ()
{
Console.WriteLine ("Generating bindings...");
Console.WriteLine ("\tLoading XML");
XmlDocument xmldoc = new XmlDocument ();
xmldoc.Load (Source);
Console.WriteLine ("\tPreprocessing");
List<Entry> entries = Preprocess (xmldoc);
Console.WriteLine ("\tPreprocessing Classes");
List<Entry> 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<Entry> Preprocess (XmlDocument xmldoc)
{
XmlNode node = xmldoc.SelectSingleNode ("/GCC_XML");
Entry.typelist = new Dictionary<string, Dictionary<string, Entry>> ();
Entry.idlist = new Dictionary<string, Entry> ();
return Preprocess (node);
}
int typecount = 0;
List<Entry> Preprocess (XmlNode parent)
{
List<Entry> data = new List<Entry> ();
foreach (XmlNode node in parent.ChildNodes) {
Dictionary<string, string> entry = new Dictionary<string, string> ();
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<Entry> ();
if (!Entry.typelist.ContainsKey (e.type))
Entry.typelist[e.type] = new Dictionary<string, Entry> ();
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<Entry> PreprocessClasses (List<Entry> entries)
{
List<string> filter = new List<string>() {
"QItemSelection"
};
List<Entry> removed = new List<Entry> (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<CppModifiers.TemplateModifier> ().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<CodeAtom> 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<Entry> entries, List<Entry> removed)
{
foreach (Entry clas in entries.Where (o => o.type == "Class" || o.type == "Struct")) {
var templated = clas.Class.OriginalType.Modifiers.OfType<CppModifiers.TemplateModifier> ().SingleOrDefault ();
Dictionary<MethodSignature, string> methods = new Dictionary<MethodSignature, string> ();
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<Type> { Name = member.attributes["mangled"], Type = typeof(ItaniumAbi) };
List<CppType> argTypes = new List<CppType> ();
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<CppType> { 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<CompilerError> ().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<CodeContainer> ().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<CodeContainer> ().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<CodeAtom> 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<Entry> 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<CodeAtom> 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<CodeAtom> 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<CppModifiers.TemplateModifier> ()) {
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<CppModifiers.TemplateModifier> ())
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<CodeAtom> dontCare;
return IsCreated (type, false, out dontCare);
}
bool IsCreated (CppType type, bool toBeCreated, out IEnumerable<CodeAtom> 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<CppModifiers.TemplateModifier> ().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<Class> ().Where (c => c.Name == type.ElementTypeName).Any () || place.Atoms.OfType<Enumeration> ().Where (e => e.Name == type.ElementTypeName).Any () || place.Atoms.OfType<Union> ().Where (u => u.Name == type.ElementTypeName).Any ();
var sameNamedNamespace = place.Atoms.OfType<Namespace> ().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<CppModifiers.TemplateModifier> ().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<Entry> removed)
{
if (entry == null)
return CppTypes.Unknown;
return findType (clas, entry, removed, new CppType ());
}
CppType findType (Class clas, Entry entry, List<Entry> 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;
}
}
}

16
src/generator/Makefile.am

@ -10,11 +10,9 @@ ASSEMBLY = bin/Debug/generator.exe @@ -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 @@ -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 @@ -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)
@ -60,11 +55,12 @@ RESGEN=resgen2 @@ -60,11 +55,12 @@ 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) @@ -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))

156
src/generator/Method.cs

@ -0,0 +1,156 @@ @@ -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<Tuple<string, CppType>> ();
}
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<Tuple<string, CppType>> 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;
}
}

64
src/generator/Node.cs

@ -0,0 +1,64 @@ @@ -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<string, string> Attributes {
get; set;
}
// The children nodes of this node
public List<Node> Children {
get; set;
}
public string this [string key] {
get {
return Attributes [key];
}
}
// Maps ids to nodes
public static Dictionary<string, Node> IdToNode = new Dictionary <string, Node> ();
// 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;
}
}
Loading…
Cancel
Save