Browse Source

Many changes to support generator. Factored CppType creating new CppModifiers class instead of enum with support for template parameters. Generator now almost produces usable code out of the box, including automatic property generation and preliminary support for wrapping templated C++ types in generic managed classes.

git-svn-id: https://mono-soc-2010.googlecode.com/svn/trunk/cppinterop@117 a470b8cb-0e6f-1642-1b45-71e107334c4b
pull/1/head
alexander.corrado 15 years ago
parent
commit
8525dd03c6
  1. 76
      Mono.VisualC.Code/Atoms/Class.cs
  2. 46
      Mono.VisualC.Code/Atoms/Enumeration.cs
  3. 63
      Mono.VisualC.Code/Atoms/Field.cs
  4. 184
      Mono.VisualC.Code/Atoms/Method.cs
  5. 4
      Mono.VisualC.Code/Atoms/Preprocessor.cs
  6. 51
      Mono.VisualC.Code/Atoms/Property.cs
  7. 59
      Mono.VisualC.Code/Atoms/Union.cs
  8. 23
      Mono.VisualC.Code/CodeAtom.cs
  9. 42
      Mono.VisualC.Code/CodeDomExtensions.cs
  10. 4
      Mono.VisualC.Code/CodeUnit.cs
  11. 5
      Mono.VisualC.Code/Mono.VisualC.Code.csproj
  12. 4
      Mono.VisualC.Interop/ABI/Impl/ItaniumTypeInfo.cs
  13. 10
      Mono.VisualC.Interop/ABI/Impl/MsvcAbi.cs
  14. 11
      Mono.VisualC.Interop/ABI/Impl/MsvcTypeInfo.cs
  15. 2
      Mono.VisualC.Interop/AssemblyInfo.cs
  16. 8
      Mono.VisualC.Interop/Attributes.cs
  17. 28
      Mono.VisualC.Interop/CppLibrary.cs
  18. 137
      Mono.VisualC.Interop/CppModifiers.cs
  19. 221
      Mono.VisualC.Interop/CppType.cs
  20. 33
      Mono.VisualC.Interop/CppTypeInfo.cs
  21. 1
      Mono.VisualC.Interop/Mono.VisualC.Interop.csproj
  22. 28
      Mono.VisualC.Interop/Util/IEnumerableTransform.cs
  23. 1
      QtTest/Main.cs
  24. 449
      generator/Main.cs
  25. 27
      generator/class.template
  26. 13
      generator/generator.csproj
  27. 3
      generator/interface.template
  28. 3
      generator/struct.template

76
Mono.VisualC.Code/Atoms/Class.cs

@ -6,6 +6,7 @@ using System.Reflection;
using System.CodeDom; using System.CodeDom;
using Mono.VisualC.Interop; using Mono.VisualC.Interop;
using Mono.VisualC.Code;
namespace Mono.VisualC.Code.Atoms { namespace Mono.VisualC.Code.Atoms {
@ -27,40 +28,48 @@ namespace Mono.VisualC.Code.Atoms {
public string StaticCppLibrary { get; set; } public string StaticCppLibrary { get; set; }
public Definition DefinedAs { get; set; } public Definition DefinedAs { get; set; }
public IEnumerable<BaseClass> Bases { get; set; } public IList<BaseClass> Bases { get; set; }
public IList<string> TemplateArguments { get; set; } public IList<string> TemplateArguments { get; set; }
public Class (string name) public Class (string name)
{ {
Name = name; Name = name;
Bases = Enumerable.Empty<BaseClass> (); Bases = new List<BaseClass> ();
TemplateArguments = new List<string> (); TemplateArguments = new List<string> ();
} }
internal protected override CodeObject InsideCodeNamespace (CodeNamespace ns) internal protected override object InsideCodeNamespace (CodeNamespace ns)
{ {
var wrapper = new CodeTypeDeclaration (Name) { TypeAttributes = TypeAttributes.Public }; var wrapper = CreateWrapperClass ();
ns.Types.Add (wrapper);
return wrapper;
}
private CodeTypeDeclaration CreateWrapperClass ()
{
var wrapper = new CodeTypeDeclaration (Name) { TypeAttributes = TypeAttributes.Public };
foreach (var arg in TemplateArguments) foreach (var arg in TemplateArguments)
wrapper.TypeParameters.Add (arg); wrapper.TypeParameters.Add (arg);
var iface = CreateInterface (); var iface = CreateInterface (wrapper);
var native = CreateNativeLayout ();
wrapper.Members.Add (iface); wrapper.Members.Add (iface);
var native = CreateNativeLayout ();
wrapper.Members.Add (native); wrapper.Members.Add (native);
// FIXME: For now, we'll have the managed wrapper extend from the first public base class // FIXME: For now, we'll have the managed wrapper extend from the first public base class
string managedBase = Bases.Where (b => b.Access == Access.Public).Select (b => b.Name).FirstOrDefault (); string managedBase = Bases.Where (b => b.Access == Access.Public).Select (b => b.Name).FirstOrDefault ();
if (managedBase == null) { bool hasOverrides = true;
if (managedBase == null) {
managedBase = typeof (ICppObject).Name; managedBase = typeof (ICppObject).Name;
hasOverrides = false;
// Add Native property // Add Native property
var nativeField = new CodeMemberField (typeof (CppInstancePtr), "native_ptr") { Attributes = MemberAttributes.Family }; var nativeField = new CodeMemberField (typeof (CppInstancePtr).Name, "native_ptr") { Attributes = MemberAttributes.Family };
var nativeProperty = new CodeMemberProperty { var nativeProperty = new CodeMemberProperty {
Name = "Native", Name = "Native",
Type = new CodeTypeReference (typeof (CppInstancePtr)), Type = new CodeTypeReference (typeof (CppInstancePtr).Name),
HasSet = false, HasSet = false,
Attributes = MemberAttributes.Public | MemberAttributes.Final Attributes = MemberAttributes.Public | MemberAttributes.Final
}; };
@ -72,26 +81,36 @@ namespace Mono.VisualC.Code.Atoms {
wrapper.BaseTypes.Add (managedBase); wrapper.BaseTypes.Add (managedBase);
// add static impl field // add static impl field
var implField = new CodeMemberField (iface.Name, "impl") { Attributes = MemberAttributes.Static | MemberAttributes.Private }; var implField = new CodeMemberField (iface.TypeReference (), "impl") { Attributes = MemberAttributes.Static | MemberAttributes.Private };
if (StaticCppLibrary != null) { if (StaticCppLibrary != null) {
CodeTypeReference [] types = new CodeTypeReference [] { CodeTypeReference [] types = new CodeTypeReference [] {
new CodeTypeReference (iface.Name), iface.TypeReference (),
new CodeTypeReference (native.Name), native.TypeReference (),
new CodeTypeReference (wrapper.Name) wrapper.TypeReference ()
}; };
var getClassMethod = new CodeMethodReferenceExpression (new CodeTypeReferenceExpression (StaticCppLibrary), "GetClass", types); var getClassMethod = new CodeMethodReferenceExpression (new CodeTypeReferenceExpression (StaticCppLibrary), "GetClass", types);
implField.InitExpression = new CodeMethodInvokeExpression (getClassMethod, new CodePrimitiveExpression (Name)); implField.InitExpression = new CodeMethodInvokeExpression (getClassMethod, new CodePrimitiveExpression (Name));
} }
wrapper.Members.Add (implField); wrapper.Members.Add (implField);
foreach (var atom in Atoms) CodeMemberMethod dispose = null;
atom.Visit (wrapper); foreach (var atom in Atoms) {
Method method = atom as Method;
if (method != null && method.IsDestructor)
dispose = (CodeMemberMethod)method.InsideCodeTypeDeclaration (wrapper);
else
atom.Visit (wrapper);
}
if (dispose == null)
wrapper.Members.Add (CreateDestructorlessDispose ());
else if (hasOverrides)
dispose.Attributes |= MemberAttributes.Override;
ns.Types.Add (wrapper);
return wrapper; return wrapper;
} }
private CodeTypeDeclaration CreateInterface () private CodeTypeDeclaration CreateInterface (CodeTypeDeclaration wrapper)
{ {
var iface = new CodeTypeDeclaration ("I" + Name) { var iface = new CodeTypeDeclaration ("I" + Name) {
TypeAttributes = TypeAttributes.Interface | TypeAttributes.NestedPublic, TypeAttributes = TypeAttributes.Interface | TypeAttributes.NestedPublic,
@ -99,7 +118,10 @@ namespace Mono.VisualC.Code.Atoms {
IsInterface = true IsInterface = true
}; };
iface.BaseTypes.Add (new CodeTypeReference (typeof (ICppClassOverridable<>).Name, new CodeTypeReference (Name))); foreach (var arg in TemplateArguments)
iface.TypeParameters.Add (arg);
iface.BaseTypes.Add (new CodeTypeReference (typeof (ICppClassOverridable<>).Name, wrapper.TypeReference ()));
foreach (var atom in Atoms) foreach (var atom in Atoms)
atom.Visit (iface); atom.Visit (iface);
@ -121,6 +143,22 @@ namespace Mono.VisualC.Code.Atoms {
return native; return native;
} }
private CodeMemberMethod CreateDestructorlessDispose ()
{
var dispose = new CodeMemberMethod {
Name = "Dispose",
Attributes = MemberAttributes.Public
};
var warning = new CodeCommentStatement ("FIXME: Check for inline destructor for this class.");
dispose.Statements.Add (warning);
var native = new CodeFieldReferenceExpression (new CodeThisReferenceExpression (), "Native");
dispose.Statements.Add (new CodeMethodInvokeExpression (native, "Dispose"));
return dispose;
}
public override void Write (TextWriter writer) public override void Write (TextWriter writer)
{ {
string declarator = (DefinedAs == Definition.Class? "class" : "struct"); string declarator = (DefinedAs == Definition.Class? "class" : "struct");

46
Mono.VisualC.Code/Atoms/Enumeration.cs

@ -0,0 +1,46 @@
using System;
using System.Linq;
using System.IO;
using System.Reflection;
using System.Collections.Generic;
using System.CodeDom;
namespace Mono.VisualC.Code.Atoms {
public class Enumeration : CodeAtom {
public struct Item {
public string Name;
public int Value;
}
public string Name { get; set; }
public IList<Item> Items { get; set; }
public Enumeration (string name)
{
Name = name;
Items = new List<Item> ();
}
internal protected override object InsideCodeNamespace (CodeNamespace ns)
{
var type = new CodeTypeDeclaration (Name) {
TypeAttributes = TypeAttributes.Public,
IsEnum = true
};
foreach (Item i in Items)
type.Members.Add (new CodeMemberField (typeof (int), i.Name) { InitExpression = new CodePrimitiveExpression (i.Value) });
ns.Types.Add (type);
return type;
}
public override void Write (TextWriter writer)
{
throw new NotImplementedException ();
}
}
}

63
Mono.VisualC.Code/Atoms/Field.cs

@ -0,0 +1,63 @@
using System;
using System.IO;
using System.CodeDom;
using Mono.VisualC.Interop;
namespace Mono.VisualC.Code.Atoms {
public class Field : CodeAtom {
public string Name { get; set; }
public CppType Type { get; set; }
public Field (string name, CppType type)
{
Name = name;
Type = type;
}
internal protected override object InsideCodeTypeDeclaration (CodeTypeDeclaration decl)
{
// FIXME: eventually this could add CppFields to the interface so they could be
// so they could be accessed as properties in the managed api
if (!decl.IsStruct)
return null;
CodeMemberField field = new CodeMemberField { Name = this.Name };
CodeTypeReference typeRef = TypeReference;
if (typeRef == null) {
field.Comments.Add (new CodeCommentStatement ("FIXME: Unknown type \"" + Type.ToString () + "\" for field \"" + Name + ".\" Assuming IntPtr."));
field.Type = new CodeTypeReference (typeof (IntPtr));
} else
field.Type = typeRef;
decl.Members.Add (field);
return field;
}
public CodeTypeReference TypeReference {
get {
if (Type.ElementType == CppTypes.Typename)
return new CodeTypeReference (Type.ElementTypeName, CodeTypeReferenceOptions.GenericTypeParameter);
if (Type.Modifiers.Contains (CppModifiers.Pointer) || Type.Modifiers.Contains (CppModifiers.Reference))
return new CodeTypeReference (typeof (IntPtr));
// FIXME: Handle arrays (fixed size?)
Type managedType = Type.ToManagedType ();
if (managedType != null)
return new CodeTypeReference (managedType);
return null;
}
}
public override void Write (TextWriter writer)
{
writer.WriteLine ("{0} {1};", Type.ToString (), Name);
}
}
}

184
Mono.VisualC.Code/Atoms/Method.cs

@ -1,4 +1,6 @@
using System; using System;
using System.Linq;
using System.Text;
using System.IO; using System.IO;
using System.Collections.Generic; using System.Collections.Generic;
using System.CodeDom; using System.CodeDom;
@ -17,64 +19,180 @@ namespace Mono.VisualC.Code.Atoms {
public Access Access { get; set; } public Access Access { get; set; }
public bool IsVirtual { get; set; } public bool IsVirtual { get; set; }
public bool IsStatic { get; set; } public bool IsStatic { get; set; }
public bool IsConst { get; set; }
public bool IsConstructor { get; set; }
public bool IsDestructor { get; set; }
public CppType RetType { get; set; } public CppType RetType { get; set; }
public IList<Parameter> Parameters { get; set; }
public IEnumerable<Parameter> Parameters { get; set; }
public Method (string name) public Method (string name)
{ {
Name = name; Name = name;
Parameters = new List<Parameter> ();
} }
internal protected override CodeObject InsideCodeTypeDeclaration (CodeTypeDeclaration decl) internal protected override object InsideCodeTypeDeclaration (CodeTypeDeclaration decl)
{ {
CodeMemberMethod method = null; if (decl.IsClass) {
var method = CreateWrapperMethod ();
decl.Members.Add (method);
return method;
} else if (decl.IsInterface)
decl.Members.Add (CreateInterfaceMethod ());
return null;
}
internal protected override object InsideCodeStatementCollection (CodeStatementCollection stmts)
{
List<CodeExpression> arguments = new List<CodeExpression> ();
if (!IsStatic)
arguments.Add (new CodeFieldReferenceExpression (new CodeThisReferenceExpression (), "Native"));
foreach (var param in Parameters) {
// FIXME: handle typenames
if (param.Type.ElementType != CppTypes.Typename) {
Type managedType = param.Type.ToManagedType ();
if (managedType != null && managedType.IsByRef) {
arguments.Add (new CodeDirectionExpression (FieldDirection.Ref, new CodeArgumentReferenceExpression (param.Name)));
continue;
}
}
arguments.Add (new CodeArgumentReferenceExpression (param.Name));
}
if (decl.IsInterface) {
method = new CodeMemberMethod { Name = this.Name };
Type managedType = RetType.ToManagedType ();
if (managedType != null && managedType.IsByRef) // FIXME: Does just specifying the field name work for all code generators?
method.ReturnType = new CodeTypeReference (typeof (IntPtr)); var impl = new CodeFieldReferenceExpression { FieldName = "impl" };
else if (managedType != null && managedType != typeof (ICppObject)) var invoke = new CodeMethodInvokeExpression (impl, Name, arguments.ToArray ());
method.ReturnType = new CodeTypeReference (managedType);
else
method.ReturnType = new CodeTypeReference (RetType.ElementTypeName);
if (IsVirtual) if (RetType.Equals (CppTypes.Void))
method.CustomAttributes.Add (new CodeAttributeDeclaration ("Virtual")); stmts.Add (invoke);
else
stmts.Add (new CodeMethodReturnStatement (invoke));
return null;
}
private CodeMemberMethod CreateInterfaceMethod ()
{
var method = new CodeMemberMethod {
Name = this.Name,
ReturnType = this.ReturnTypeReference
};
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 (IsStatic)
method.CustomAttributes.Add (new CodeAttributeDeclaration ("Static"));
else
method.Parameters.Add (new CodeParameterDeclarationExpression (typeof (CppInstancePtr).Name, "this"));
AddParameters (method, true);
return method;
}
private CodeMemberMethod CreateWrapperMethod ()
{
CodeMemberMethod method;
if (IsConstructor)
method = new CodeConstructor {
Name = FormattedName,
Attributes = MemberAttributes.Public
};
else if (IsDestructor)
method = new CodeMemberMethod {
Name = "Dispose",
Attributes = MemberAttributes.Public
};
else
method = new CodeMemberMethod {
Name = FormattedName,
Attributes = MemberAttributes.Public,
ReturnType = ReturnTypeReference
};
if (IsStatic)
method.Attributes |= MemberAttributes.Static;
else if (!IsVirtual && !IsDestructor)
// I'm only making methods that are virtual in C++ virtual in managed code.
// I think it is the right thing to do because the consumer of the API might not
// get the intended effect if the managed method is overridden and the native method is not.
method.Attributes |= MemberAttributes.Final;
else if (IsVirtual && !IsDestructor)
method.CustomAttributes.Add (new CodeAttributeDeclaration ("OverrideNative"));
AddParameters (method, false);
return method;
}
if (IsStatic) public CodeTypeReference ReturnTypeReference {
method.CustomAttributes.Add (new CodeAttributeDeclaration ("Static")); get {
else CodeTypeReference returnType;
method.Parameters.Add (new CodeParameterDeclarationExpression (typeof (CppInstancePtr).Name, "this"));
if (RetType.ElementType == CppTypes.Typename)
returnType = new CodeTypeReference (RetType.ElementTypeName, CodeTypeReferenceOptions.GenericTypeParameter);
else {
Type managedType = RetType.ToManagedType ();
if (managedType != null && managedType.IsByRef)
returnType = new CodeTypeReference (typeof (IntPtr));
else if (managedType != null && managedType != typeof (ICppObject))
returnType = new CodeTypeReference (managedType);
else
returnType = RetType.TypeReference ();
}
foreach (var param in Parameters) { return returnType;
}
}
CodeParameterDeclarationExpression paramDecl; private void AddParameters (CodeMemberMethod method, bool includeMangleAttribute)
managedType = param.Type.ToManagedType (); {
foreach (var param in Parameters) {
CodeParameterDeclarationExpression paramDecl;
// BOO work around bug in Codedom dealing with byref types! if (param.Type.ElementType == CppTypes.Typename)
paramDecl = new CodeParameterDeclarationExpression (param.Type.ElementTypeName, param.Name);
else {
Type managedType = param.Type.ToManagedType ();
if (managedType != null && managedType.IsByRef) if (managedType != null && managedType.IsByRef)
paramDecl = new CodeParameterDeclarationExpression (managedType.GetElementType (), param.Name) { Direction = FieldDirection.Ref }; paramDecl = new CodeParameterDeclarationExpression (managedType.GetElementType (), param.Name) { Direction = FieldDirection.Ref };
else if (managedType != null && managedType != typeof (ICppObject)) else if (managedType != null && managedType != typeof (ICppObject))
paramDecl = new CodeParameterDeclarationExpression (managedType, param.Name); paramDecl = new CodeParameterDeclarationExpression (managedType, param.Name);
else else
paramDecl = new CodeParameterDeclarationExpression (param.Type.ElementTypeName, param.Name); paramDecl = new CodeParameterDeclarationExpression (param.Type.TypeReference (), param.Name);
}
// FIXME: Only add MangleAs attribute if the managed type chosen would mangle differently by default // FIXME: Only add MangleAs attribute if the managed type chosen would mangle differently by default
if (!IsVirtual) string paramStr = param.Type.ToString ();
paramDecl.CustomAttributes.Add (new CodeAttributeDeclaration ("MangleAs", new CodeAttributeArgument (new CodePrimitiveExpression (param.Type.ToString ())))); if (includeMangleAttribute && !IsVirtual && !paramStr.Equals (string.Empty))
paramDecl.CustomAttributes.Add (new CodeAttributeDeclaration ("MangleAs", new CodeAttributeArgument (new CodePrimitiveExpression (paramStr))));
method.Parameters.Add (paramDecl); method.Parameters.Add (paramDecl);
}
} }
}
// FIXME: add wrapper method public string FormattedName {
if (method != null) get {
decl.Members.Add (method); string upper = Name.ToUpper ();
return method; StringBuilder sb = new StringBuilder (Name.Length);
for (int i = 0; i < Name.Length; i++) {
if (i == 0)
sb.Append (upper [0]);
else if (Name [i] == '_')
sb.Append (upper [++i]);
else
sb.Append (Name [i]);
}
return sb.ToString ();
}
} }
public override void Write (TextWriter writer) public override void Write (TextWriter writer)

4
Mono.VisualC.Code/Atoms/Preprocessor.cs

@ -29,7 +29,7 @@ namespace Mono.VisualC.Code.Atoms {
writer.WriteLine ("#define {0}", Name); writer.WriteLine ("#define {0}", Name);
} }
internal protected override CodeObject InsideCodeNamespace (CodeNamespace ns) internal protected override object InsideCodeNamespace (CodeNamespace ns)
{ {
if (!value_set) if (!value_set)
return null; return null;
@ -46,7 +46,7 @@ namespace Mono.VisualC.Code.Atoms {
return constants; return constants;
} }
internal protected override CodeObject InsideCodeTypeDeclaration (CodeTypeDeclaration decl) internal protected override object InsideCodeTypeDeclaration (CodeTypeDeclaration decl)
{ {
if (!value_set) if (!value_set)
return null; return null;

51
Mono.VisualC.Code/Atoms/Property.cs

@ -0,0 +1,51 @@
using System;
using System.IO;
using System.CodeDom;
namespace Mono.VisualC.Code.Atoms {
public class Property : CodeAtom {
public string Name { get; set; }
public Method Getter { get; set; }
public Method Setter { get; set; }
public Property (string name)
{
Name = name;
}
internal protected override object InsideCodeTypeDeclaration (CodeTypeDeclaration decl)
{
// if getter is omitted, just output the setter like a method
if (decl.IsInterface || Getter == null) {
if (Getter != null)
Getter.Visit (decl);
if (Setter != null)
Setter.Visit (decl);
return null;
} else if (!decl.IsClass)
return null;
var prop = new CodeMemberProperty {
Name = this.Name,
// FIXME: For now, no properties will be virtual... change this at some point?
Attributes = MemberAttributes.Public | MemberAttributes.Final,
Type = Getter.ReturnTypeReference
};
Getter.Visit (prop.GetStatements);
if (Setter != null)
Setter.Visit (prop.SetStatements);
decl.Members.Add (prop);
return prop;
}
public override void Write (TextWriter writer)
{
throw new NotImplementedException ();
}
}
}

59
Mono.VisualC.Code/Atoms/Union.cs

@ -0,0 +1,59 @@
using System;
using System.IO;
using System.CodeDom;
using System.Reflection;
using System.Runtime.InteropServices;
namespace Mono.VisualC.Code.Atoms {
public class Union : CodeContainer {
public string Name { get; set; }
public Union (string name)
{
Name = name;
}
public CodeTypeDeclaration CreateUnionType ()
{
var union = new CodeTypeDeclaration (Name) {
Attributes = MemberAttributes.Public,
TypeAttributes = TypeAttributes.Public | TypeAttributes.ExplicitLayout,
IsStruct = true
};
foreach (var atom in Atoms) {
Field field = atom as Field;
if (field == null)
throw new Exception ("Only Fields allowed in Union.");
CodeMemberField cmf = field.InsideCodeTypeDeclaration (union) as CodeMemberField;
if (cmf != null)
cmf.CustomAttributes.Add (new CodeAttributeDeclaration (new CodeTypeReference (typeof (FieldOffsetAttribute)), new CodeAttributeArgument (new CodePrimitiveExpression (0))));
}
return union;
}
internal protected override object InsideCodeNamespace (CodeNamespace ns)
{
ns.Types.Add (CreateUnionType ());
return null;
}
internal protected override object InsideCodeTypeDeclaration (CodeTypeDeclaration decl)
{
decl.Members.Add (CreateUnionType ());
return null;
}
public override void Write (TextWriter writer)
{
writer.WriteLine ("union {0} {{", Name);
base.Write (writer);
writer.WriteLine ("}");
}
}
}

23
Mono.VisualC.Code/CodeAtom.cs

@ -9,34 +9,39 @@ namespace Mono.VisualC.Code {
public abstract class CodeAtom { public abstract class CodeAtom {
internal protected virtual void Visit (CodeObject obj) internal protected virtual void Visit (object obj)
{ {
CodeObject result = obj; object result = obj;
while (result != null) { while (result != null) {
if (result is CodeCompileUnit) { result = InsideCodeCompileUnit (result as CodeCompileUnit); continue; } if (result is CodeCompileUnit) { result = InsideCodeCompileUnit (result as CodeCompileUnit); continue; }
if (result is CodeNamespace) { result = InsideCodeNamespace (result as CodeNamespace); continue; } if (result is CodeNamespace) { result = InsideCodeNamespace (result as CodeNamespace); continue; }
if (result is CodeTypeDeclaration) { result = InsideCodeTypeDeclaration (result as CodeTypeDeclaration); continue; } if (result is CodeTypeDeclaration) { result = InsideCodeTypeDeclaration (result as CodeTypeDeclaration); continue; }
if (result is CodeMemberMethod) { result = InsideCodeStatementCollection (((CodeMemberMethod)result).Statements); continue; }
if (result is CodeStatementCollection) { result = InsideCodeStatementCollection (result as CodeStatementCollection); continue; }
break; break;
} }
} }
internal protected virtual CodeObject InsideCodeCompileUnit (CodeCompileUnit ccu) internal protected virtual object InsideCodeCompileUnit (CodeCompileUnit ccu)
{ {
return null; return null;
} }
internal protected virtual CodeObject InsideCodeNamespace (CodeNamespace ns) internal protected virtual object InsideCodeNamespace (CodeNamespace ns)
{ {
return null; return null;
} }
internal protected virtual CodeObject InsideCodeTypeDeclaration (CodeTypeDeclaration decl) internal protected virtual object InsideCodeTypeDeclaration (CodeTypeDeclaration decl)
{ {
return null; return null;
} }
internal protected virtual object InsideCodeStatementCollection (CodeStatementCollection stmts)
{
return null;
}
public abstract void Write (TextWriter writer); public abstract void Write (TextWriter writer);
} }
} }

42
Mono.VisualC.Code/CodeDomExtensions.cs

@ -0,0 +1,42 @@
using System;
using System.Linq;
using System.Text;
using System.CodeDom;
using Mono.VisualC.Interop;
namespace Mono.VisualC.Code {
public static class CodeDomExtensions {
public static CodeTypeReference TypeReference (this CodeTypeDeclaration ctd)
{
return new CodeTypeReference (ctd.Name, ctd.TypeParameterReferences ());
}
public static CodeTypeReference TypeReference (this CppType t)
{
return t.TypeReference (false);
}
public static CodeTypeReference TypeReference (this CppType t, bool useManagedType)
{
var tempParm = from m in t.Modifiers.OfType<CppModifiers.TemplateModifier> ()
from p in m.Types
select p.TypeReference (true);
Type managedType = useManagedType? t.ToManagedType () : null;
if (managedType == typeof (ICppObject))
managedType = null;
return new CodeTypeReference (managedType.FullName ?? t.ElementTypeName, tempParm.ToArray ());
}
public static CodeTypeReference [] TypeParameterReferences (this CodeTypeDeclaration ctd)
{
return ctd.TypeParameters.Cast<CodeTypeParameter> ().Select (p => new CodeTypeReference (p)).ToArray ();
}
}
}

4
Mono.VisualC.Code/CodeUnit.cs

@ -22,7 +22,7 @@ namespace Mono.VisualC.Code {
return ccu; return ccu;
} }
internal protected override CodeObject InsideCodeCompileUnit (CodeCompileUnit ccu) internal protected override object InsideCodeCompileUnit (CodeCompileUnit ccu)
{ {
CodeNamespace ns = new CodeNamespace (ManagedNamespace); CodeNamespace ns = new CodeNamespace (ManagedNamespace);
ns.Imports.Add (new CodeNamespaceImport ("Mono.VisualC.Interop")); ns.Imports.Add (new CodeNamespaceImport ("Mono.VisualC.Interop"));
@ -31,7 +31,7 @@ namespace Mono.VisualC.Code {
return ns; return ns;
} }
internal protected override CodeObject InsideCodeNamespace (CodeNamespace ns) internal protected override object InsideCodeNamespace (CodeNamespace ns)
{ {
foreach (var atom in Atoms) foreach (var atom in Atoms)
atom.Visit (ns); atom.Visit (ns);

5
Mono.VisualC.Code/Mono.VisualC.Code.csproj

@ -41,6 +41,11 @@
<Compile Include="CodeUnit.cs" /> <Compile Include="CodeUnit.cs" />
<Compile Include="Access.cs" /> <Compile Include="Access.cs" />
<Compile Include="Atoms\Method.cs" /> <Compile Include="Atoms\Method.cs" />
<Compile Include="Atoms\Enumeration.cs" />
<Compile Include="CodeDomExtensions.cs" />
<Compile Include="Atoms\Property.cs" />
<Compile Include="Atoms\Field.cs" />
<Compile Include="Atoms\Union.cs" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup> <ItemGroup>

4
Mono.VisualC.Interop/ABI/Impl/ItaniumTypeInfo.cs

@ -11,6 +11,7 @@ namespace Mono.VisualC.Interop.ABI {
public ItaniumTypeInfo (ItaniumAbi abi, IEnumerable<MethodInfo> virtualMethods, Type nativeLayout) public ItaniumTypeInfo (ItaniumAbi abi, IEnumerable<MethodInfo> virtualMethods, Type nativeLayout)
: base (abi, virtualMethods, nativeLayout) : base (abi, virtualMethods, nativeLayout)
{ {
// Remove all virtual destructors from their declared position in the vtable
for (int i = 0; i < VirtualMethods.Count; i++) { for (int i = 0; i < VirtualMethods.Count; i++) {
if (Abi.GetMethodType (VirtualMethods [i]) != MethodType.NativeDtor) if (Abi.GetMethodType (VirtualMethods [i]) != MethodType.NativeDtor)
continue; continue;
@ -27,6 +28,9 @@ namespace Mono.VisualC.Interop.ABI {
public override void AddBase (CppTypeInfo baseType) public override void AddBase (CppTypeInfo baseType)
{ {
if (TypeComplete)
return;
hasVirtualDtor |= ((ItaniumTypeInfo)baseType).HasVirtualDestructor; hasVirtualDtor |= ((ItaniumTypeInfo)baseType).HasVirtualDestructor;
base.AddBase (baseType); base.AddBase (baseType);
} }

10
Mono.VisualC.Interop/ABI/Impl/MsvcAbi.cs

@ -77,9 +77,13 @@ namespace Mono.VisualC.Interop.ABI {
nm.Append (funcModifier); nm.Append (funcModifier);
// FIXME: deal with storage classes for "this" i.e. the "const" in -> int foo () const; // FIXME: deal with other storage classes for "this" i.e. the "volatile" in -> int foo () volatile;
if (!IsStatic (methodInfo)) if (!IsStatic (methodInfo)) {
nm.Append ('A'); if (IsConst (methodInfo))
nm.Append ('B');
else
nm.Append ('A');
}
switch (GetCallingConvention (methodInfo)) { switch (GetCallingConvention (methodInfo)) {
case CallingConvention.Cdecl: case CallingConvention.Cdecl:

11
Mono.VisualC.Interop/ABI/Impl/MsvcTypeInfo.cs

@ -18,13 +18,10 @@ namespace Mono.VisualC.Interop.ABI {
if (TypeComplete) if (TypeComplete)
return; return;
if (BaseClasses.Count == 0) { if (BaseClasses.Count == 0)
base.AddBase (baseType); base.AddBase (baseType, false);
return; else
} base.AddBase (baseType, true);
BaseClasses.Add (baseType);
field_offset_padding += baseType.NativeSize;
} }
} }

2
Mono.VisualC.Interop/AssemblyInfo.cs

@ -30,5 +30,5 @@ using System.Runtime.CompilerServices;
//[assembly: AssemblyKeyFile("")] //[assembly: AssemblyKeyFile("")]
[assembly: CLSCompliant(true)] [assembly: CLSCompliant(true)]
// TODO: This will not work if we ever support saving these assemblies // FIXME: This will not work if we ever support saving these assemblies
[assembly: InternalsVisibleTo("__CppLibraryImplAssembly")] [assembly: InternalsVisibleTo("__CppLibraryImplAssembly")]

8
Mono.VisualC.Interop/Attributes.cs

@ -28,6 +28,10 @@ namespace Mono.VisualC.Interop {
[AttributeUsage (AttributeTargets.Method)] [AttributeUsage (AttributeTargets.Method)]
public class StaticAttribute : Attribute {} public class StaticAttribute : Attribute {}
// used for the const "this" - for example: int value () const;
[AttributeUsage (AttributeTargets.Method)]
public class ConstAttribute : Attribute {}
// FIXME: Will we ever be calling private methods? // FIXME: Will we ever be calling private methods?
[AttributeUsage (AttributeTargets.Method)] [AttributeUsage (AttributeTargets.Method)]
public class PrivateAttribute : Attribute {} public class PrivateAttribute : Attribute {}
@ -71,6 +75,10 @@ using Mono.VisualC.Interop;
{ {
return method.IsDefined (typeof (StaticAttribute), false); return method.IsDefined (typeof (StaticAttribute), false);
} }
public virtual bool IsConst (MethodInfo method)
{
return method.IsDefined (typeof (ConstAttribute), false);
}
public virtual bool IsPrivate (MethodInfo method) public virtual bool IsPrivate (MethodInfo method)
{ {
return method.IsDefined (typeof (PrivateAttribute), false); return method.IsDefined (typeof (PrivateAttribute), false);

28
Mono.VisualC.Interop/CppLibrary.cs

@ -23,8 +23,8 @@ namespace Mono.VisualC.Interop {
internal static AssemblyBuilder interopAssembly; internal static AssemblyBuilder interopAssembly;
internal static ModuleBuilder interopModule; internal static ModuleBuilder interopModule;
private CppAbi abi; public CppAbi Abi { get; private set; }
private string name; public string Name { get; private set; }
static CppLibrary () static CppLibrary ()
{ {
@ -35,6 +35,18 @@ namespace Mono.VisualC.Interop {
interopModule = interopAssembly.DefineDynamicModule (moduleName, moduleName, true); interopModule = interopAssembly.DefineDynamicModule (moduleName, moduleName, true);
} }
public CppLibrary (string name)
{
if (name == null)
throw new ArgumentNullException ("Name cannot be NULL.");
this.Name = name;
// FIXME: This is where we'd auto detect the ABI
this.Abi = new ItaniumAbi ();
}
public CppLibrary (string name, CppAbi abi) public CppLibrary (string name, CppAbi abi)
{ {
@ -43,16 +55,8 @@ namespace Mono.VisualC.Interop {
if (abi == null) if (abi == null)
throw new ArgumentNullException ("Abi cannot be NULL."); throw new ArgumentNullException ("Abi cannot be NULL.");
this.name = name; this.Name = name;
this.abi = abi; this.Abi = abi;
}
public string Name {
get { return name; }
}
public CppAbi Abi {
get { return abi; }
} }
// Mainly for debugging at this point // Mainly for debugging at this point

137
Mono.VisualC.Interop/CppModifiers.cs

@ -0,0 +1,137 @@
//
// Mono.VisualC.Interop.CppModifiers.cs: Abstracts a C++ type modifiers
//
// Author:
// Alexander Corrado (alexander.corrado@gmail.com)
//
// Copyright (C) 2010 Alexander Corrado
//
using System;
using System.Linq;
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace Mono.VisualC.Interop {
public abstract class CppModifiers {
// This can be added to at runtime to support other modifiers
public static readonly Dictionary<string,Func<Match,CppModifiers>> Tokenize = new Dictionary<string,Func<Match,CppModifiers>> () {
{ "\\bconst\\b", m => CppModifiers.Const },
{ "\\*", m => CppModifiers.Pointer },
{ "\\[([^\\]]*)\\]", m => m.Groups [1].Success && m.Groups [1].Value.Trim () != ""? new ArrayModifier (int.Parse (m.Groups [1].Value)) : CppModifiers.Array },
{ "\\&", m => CppModifiers.Reference },
{ "\\bvolatile\\b", m => CppModifiers.Volatile },
{ "\\bsigned\\b", m => CppModifiers.Signed },
{ "\\bunsigned\\b", m => CppModifiers.Unsigned },
{ "\\bshort\\b", m => CppModifiers.Short },
{ "\\blong\\b", m => CppModifiers.Long },
{ "\\<(.*)\\>", m => m.Groups [1].Success && m.Groups [1].Value.Trim () != ""? new TemplateModifier (m.Groups [1].Value) : CppModifiers.Template }
};
public static IEnumerable<CppModifiers> Parse (string input)
{
foreach (var token in Tokenize) {
foreach (Match match in Regex.Matches (input, token.Key))
yield return token.Value (match);
}
}
public static string Remove (string input)
{
foreach (var token in Tokenize)
input = Regex.Replace (input, token.Key, "");
return input;
}
public override bool Equals (object obj)
{
if (obj == null)
return false;
return GetType ().Equals (obj.GetType ());
}
public override int GetHashCode ()
{
return GetType ().GetHashCode ();
}
public static bool operator == (CppModifiers a, CppModifiers b)
{
if (a != null && b != null)
return a.Equals (b);
if (a == null && b == null)
return true;
return false;
}
public static bool operator != (CppModifiers a, CppModifiers b)
{
return !(a == b);
}
public static readonly CppModifiers Const = new ConstModifier ();
public static readonly CppModifiers Pointer = new PointerModifier ();
public static readonly CppModifiers Array = new ArrayModifier ();
public static readonly CppModifiers Reference = new ReferenceModifier ();
public static readonly CppModifiers Volatile = new VolatileModifier ();
public static readonly CppModifiers Signed = new SignedModifier ();
public static readonly CppModifiers Unsigned = new UnsignedModifier ();
public static readonly CppModifiers Short = new ShortModifier ();
public static readonly CppModifiers Long = new LongModifier ();
public static readonly CppModifiers Template = new TemplateModifier ();
// Add list of modifiers here:
public class ConstModifier : CppModifiers { public override string ToString () { return "const"; } }
public class PointerModifier : CppModifiers { public override string ToString () { return "*"; } }
public class ReferenceModifier : CppModifiers { public override string ToString () { return "&"; } }
public class VolatileModifier : CppModifiers { public override string ToString () { return "volatile"; } }
public class SignedModifier : CppModifiers { public override string ToString () { return "signed"; } }
public class UnsignedModifier : CppModifiers { public override string ToString () { return "unsigned"; } }
public class ShortModifier : CppModifiers { public override string ToString () { return "short"; } }
public class LongModifier : CppModifiers { public override string ToString () { return "long"; } }
public class ArrayModifier : CppModifiers {
public int? Size { get; set; }
public ArrayModifier ()
{
}
public ArrayModifier (int size) {
Size = size;
}
public override string ToString ()
{
return string.Format ("[{0}]", Size.HasValue? Size.ToString () : "");
}
}
public class TemplateModifier : CppModifiers {
public CppType [] Types { get; set; }
public TemplateModifier ()
{
}
public TemplateModifier (string types)
{
Types = Regex.Split (types, "(?<!\\<[^\\>]*),").Select (p => new CppType (p)).ToArray ();
}
public TemplateModifier (CppType [] types)
{
Types = types;
}
public override string ToString ()
{
return string.Format ("<{0}>", Types == null? "" : string.Join (", ", Types.Select (t => t.ToString ()).ToArray ()));
}
}
}
}

221
Mono.VisualC.Interop/CppType.cs

@ -18,18 +18,7 @@ using Mono.VisualC.Interop.Util;
namespace Mono.VisualC.Interop { namespace Mono.VisualC.Interop {
public enum CppModifiers { // These can be used anywhere a CppType could be used.
Const,
Pointer,
Array,
Reference,
Volatile,
// ---
Signed,
Unsigned,
Short,
Long
}
public enum CppTypes { public enum CppTypes {
Unknown, Unknown,
Class, Class,
@ -41,23 +30,13 @@ namespace Mono.VisualC.Interop {
Char, Char,
Int, Int,
Float, Float,
Double Double,
// for template type parameters
Typename
} }
public struct CppType { public struct CppType {
public static Dictionary<string,CppModifiers> Tokenize = new Dictionary<string, CppModifiers> () {
{ "\\*", CppModifiers.Pointer },
{ "\\[\\s*\\]", CppModifiers.Array },
{ "\\&", CppModifiers.Reference }
};
public static Dictionary<CppModifiers,string> Stringify = new Dictionary<CppModifiers, string> () {
{ CppModifiers.Pointer, "*" },
{ CppModifiers.Array, "[]" },
{ CppModifiers.Reference, "&" }
};
// FIXME: Passing these as delegates allows for the flexibility of doing processing on the // FIXME: Passing these as delegates allows for the flexibility of doing processing on the
// type (i.e. to correctly mangle the function pointer arguments if the managed type is a delegate), // type (i.e. to correctly mangle the function pointer arguments if the managed type is a delegate),
// however this does not make it very easy to override the default mappings at runtime. // however this does not make it very easy to override the default mappings at runtime.
@ -73,15 +52,18 @@ namespace Mono.VisualC.Interop {
// single pointer to char gets string // single pointer to char gets string
(t) => t.ElementType == CppTypes.Char && t.Modifiers.Count (m => m == CppModifiers.Pointer) == 1? typeof (string) : null, (t) => t.ElementType == CppTypes.Char && t.Modifiers.Count (m => m == CppModifiers.Pointer) == 1? typeof (string) : null,
// pointer to pointer to char gets StringBuilder // pointer to pointer to char gets string[]
(t) => t.ElementType == CppTypes.Char && t.Modifiers.Count (m => m == CppModifiers.Pointer) == 2? typeof (StringBuilder) : null, (t) => t.ElementType == CppTypes.Char && t.Modifiers.Count (m => m == CppModifiers.Pointer) == 2? typeof (string).MakeArrayType () : null,
// arrays
(t) => t.Modifiers.Contains (CppModifiers.Array)? t.Subtract (CppModifiers.Array).ToManagedType ().MakeArrayType () : null,
// convert single pointers to primatives to managed byref // convert single pointers to primatives to managed byref
(t) => t.Modifiers.Count (m => m == CppModifiers.Pointer) == 1? t.WithoutModifier (CppModifiers.Pointer).ToManagedType ().MakeByRefType () : null, (t) => t.Modifiers.Count (m => m == CppModifiers.Pointer) == 1? t.Subtract (CppModifiers.Pointer).ToManagedType ().MakeByRefType () : null,
// more than one level of indirection gets IntPtr type // more than one level of indirection gets IntPtr type
(t) => t.Modifiers.Contains (CppModifiers.Pointer)? typeof (IntPtr) : null, (t) => t.Modifiers.Contains (CppModifiers.Pointer)? typeof (IntPtr) : null,
(t) => t.Modifiers.Contains (CppModifiers.Reference)? t.WithoutModifier (CppModifiers.Reference).ToManagedType ().MakeByRefType () : null, (t) => t.Modifiers.Contains (CppModifiers.Reference)? t.Subtract (CppModifiers.Reference).ToManagedType ().MakeByRefType () : null,
(t) => t.ElementType == CppTypes.Int && t.Modifiers.Contains (CppModifiers.Short) && t.Modifiers.Contains (CppModifiers.Unsigned)? typeof (ushort) : null, (t) => t.ElementType == CppTypes.Int && t.Modifiers.Contains (CppModifiers.Short) && t.Modifiers.Contains (CppModifiers.Unsigned)? typeof (ushort) : null,
(t) => t.ElementType == CppTypes.Int && t.Modifiers.Contains (CppModifiers.Long) && t.Modifiers.Contains (CppModifiers.Unsigned)? typeof (ulong) : null, (t) => t.ElementType == CppTypes.Int && t.Modifiers.Contains (CppModifiers.Long) && t.Modifiers.Contains (CppModifiers.Unsigned)? typeof (ulong) : null,
@ -143,6 +125,8 @@ namespace Mono.VisualC.Interop {
// this will contain the name of said type // this will contain the name of said type
public string ElementTypeName { get; set; } public string ElementTypeName { get; set; }
// this is initialized lazily to avoid unnecessary heap
// allocations if possible
private List<CppModifiers> internalModifiers; private List<CppModifiers> internalModifiers;
public List<CppModifiers> Modifiers { public List<CppModifiers> Modifiers {
get { get {
@ -156,7 +140,7 @@ namespace Mono.VisualC.Interop {
// here, you can pass in things like "const char*" or "const Foo * const" // here, you can pass in things like "const char*" or "const Foo * const"
// DISCLAIMER: this is really just for convenience for now, and is not meant to be able // DISCLAIMER: this is really just for convenience for now, and is not meant to be able
// to parse even moderately complex C++ type declarations. // to parse even moderately complex C++ type declarations.
public CppType (string type) : this (Regex.Split (type, "\\s+(?!\\])")) public CppType (string type) : this (Regex.Split (type, "\\s+(?![^\\>]*\\>|[^\\[\\]]*\\])"))
{ {
} }
@ -168,67 +152,55 @@ namespace Mono.VisualC.Interop {
Parse (cppTypeSpec); Parse (cppTypeSpec);
} }
private void Parse (object [] modifiers) private void Parse (object [] parts)
{ {
for (int i = 0; i < modifiers.Length; i++) { foreach (object part in parts) {
if (modifiers [i] is CppModifiers) { if (part is CppModifiers) {
Modifiers.Add ((CppModifiers)modifiers [i]); Modifiers.Add ((CppModifiers)part);
continue; continue;
} }
string strModifier = modifiers [i] as string; if (part is CppModifiers []) {
if (strModifier != null) { Modifiers.AddRange ((CppModifiers [])part);
// FIXME: Use Enum.TryParse here if we decide to make this NET_4_0 only continue;
try {
Modifiers.Add ((CppModifiers)Enum.Parse (typeof (CppModifiers), strModifier, true));
continue;
} catch { }
} }
// must be a type name if (part is CppTypes) {
ParseType (modifiers [i]); ElementType = (CppTypes)part;
} continue;
}
private void ParseType (object type)
{
if (type is CppTypes) {
ElementType = (CppTypes)type;
ElementTypeName = null;
return;
}
string strType = type as string;
if (strType != null) {
// strip tokens off type name
foreach (var token in Tokenize) {
foreach (var match in Regex.Matches (strType, token.Key))
Modifiers.Add (token.Value);
strType = Regex.Replace (strType, token.Key, string.Empty);
} }
// FIXME: Use Enum.TryParse here if we decide to make this NET_4_0 only Type managedType = part as Type;
try { if (managedType != null) {
CppTypes parsed = (CppTypes)Enum.Parse (typeof (CppTypes), strType, true); CppType mapped = CppType.ForManagedType (managedType);
ElementType = parsed; ApplyTo (mapped);
ElementTypeName = null; continue;
return; }
} catch { }
// it's the element type name
strType = strType.Trim ();
if (!strType.Equals (string.Empty))
ElementTypeName = strType;
return;
}
Type managedType = type as Type; string strPart = part as string;
if (managedType != null) { if (strPart != null) {
CppType mapped = CppType.ForManagedType (managedType); var parsed = CppModifiers.Parse (strPart);
ApplyTo (mapped); if (parsed.Any ()) {
return; Modifiers.AddRange (parsed);
strPart = CppModifiers.Remove (strPart);
}
// if we have something left, it must be a type name
strPart = strPart.Trim ();
if (strPart != "") {
// FIXME: Use Enum.TryParse here if we decide to make this NET_4_0 only
try {
CppTypes cppTypes = (CppTypes)Enum.Parse (typeof (CppTypes), strPart, true);
ElementType = cppTypes;
continue;
} catch { }
// otherwise it is the element type name...
ElementTypeName = strPart;
}
}
} }
} }
@ -242,7 +214,7 @@ namespace Mono.VisualC.Interop {
ElementTypeName = type.ElementTypeName; ElementTypeName = type.ElementTypeName;
List<CppModifiers> oldModifiers = internalModifiers; List<CppModifiers> oldModifiers = internalModifiers;
internalModifiers = type.Modifiers; internalModifiers = type.internalModifiers;
if (oldModifiers != null) if (oldModifiers != null)
Modifiers.AddRange (oldModifiers); Modifiers.AddRange (oldModifiers);
@ -250,33 +222,54 @@ namespace Mono.VisualC.Interop {
return this; return this;
} }
// Removes the modifiers from the passed instance from this instance // Removes the modifiers on the passed instance from this instance
public CppType Subtract (CppType type) public CppType Subtract (CppType type)
{ {
if (internalModifiers == null) if (internalModifiers == null)
return this; return this;
foreach (var modifier in type.Modifiers) { CppType current = this;
for (int i = 0; i < internalModifiers.Count; i++) { foreach (var modifier in ((IEnumerable<CppModifiers>)type.Modifiers).Reverse ())
if (internalModifiers [i] == modifier) current = current.Subtract (modifier);
internalModifiers.RemoveAt (i--);
}
}
return this; return current;
}
public CppType Subtract (CppModifiers modifier)
{
CppType newType = this;
newType.internalModifiers = new List<CppModifiers> (((IEnumerable<CppModifiers>)newType.Modifiers).Reverse ().WithoutFirst (modifier));
return newType;
}
// note: this adds modifiers "backwards" (it is mainly used by the generator)
public CppType Modify (CppModifiers modifier)
{
CppType newType = this;
var newModifier = new CppModifiers [] { modifier };
if (newType.internalModifiers != null)
newType.internalModifiers.AddFirst (newModifier);
else
newType.internalModifiers = new List<CppModifiers> (newModifier);
return newType;
} }
public override bool Equals (object obj) public override bool Equals (object obj)
{ {
if (obj == null) if (obj == null)
return false; return false;
if (obj.GetType () != typeof(CppType)) if (obj.GetType () == typeof (CppTypes))
return Equals (new CppType (obj));
if (obj.GetType () != typeof (CppType))
return false; return false;
CppType other = (CppType)obj; CppType other = (CppType)obj;
// FIXME: the order of some modifiers is not significant // FIXME: the order of some modifiers is not significant
return ((internalModifiers == null && other.internalModifiers == null) || return (((internalModifiers == null || !internalModifiers.Any ()) &&
internalModifiers.SequenceEqual (other.internalModifiers)) && (other.internalModifiers == null || !other.internalModifiers.Any ())) ||
(internalModifiers != null && other.internalModifiers != null &&
internalModifiers.SequenceEqual (other.internalModifiers))) &&
ElementType == other.ElementType && ElementType == other.ElementType &&
ElementTypeName == other.ElementTypeName; ElementTypeName == other.ElementTypeName;
} }
@ -291,23 +284,27 @@ namespace Mono.VisualC.Interop {
} }
} }
public override string ToString () public override string ToString ()
{ {
StringBuilder cppTypeString = new StringBuilder (); StringBuilder cppTypeString = new StringBuilder ();
if (ElementType != CppTypes.Unknown) if (ElementType != CppTypes.Unknown && ElementType != CppTypes.Typename)
cppTypeString.Append (Enum.GetName (typeof (CppTypes), ElementType).ToLower ()); cppTypeString.Append (Enum.GetName (typeof (CppTypes), ElementType).ToLower ());
if (ElementTypeName != null) if (ElementTypeName != null && ElementType != CppTypes.Typename) {
cppTypeString.Append (" ").Append (ElementTypeName); if (cppTypeString.Length > 0)
cppTypeString.Append (' ');
cppTypeString.Append (ElementTypeName);
}
foreach (var modifier in Modifiers) { if (internalModifiers != null) {
string stringified; foreach (var modifier in internalModifiers) {
if (!Stringify.TryGetValue (modifier, out stringified)) string stringified = modifier.ToString ();
stringified = Enum.GetName (typeof (CppModifiers), modifier).ToLower ();
cppTypeString.Append (" ").Append (stringified); if (cppTypeString.Length > 0)
cppTypeString.Append (' ');
cppTypeString.Append (stringified);
}
} }
return cppTypeString.ToString (); return cppTypeString.ToString ();
@ -323,26 +320,6 @@ namespace Mono.VisualC.Interop {
return mappedType; return mappedType;
} }
public CppType Modify (CppModifiers modifier)
{
CppType newType = this;
var newModifier = new CppModifiers [] { modifier };
if (newType.internalModifiers != null)
newType.internalModifiers.AddFirst (newModifier);
else
newType.internalModifiers = new List<CppModifiers> (newModifier);
return newType;
}
public CppType WithoutModifier (CppModifiers modifier)
{
CppType newType = this;
newType.internalModifiers = new List<CppModifiers> (newType.Modifiers.Without (modifier));
return newType;
}
public static CppType ForManagedType (Type type) public static CppType ForManagedType (Type type)
{ {

33
Mono.VisualC.Interop/CppTypeInfo.cs

@ -67,17 +67,29 @@ namespace Mono.VisualC.Interop {
if (TypeComplete) if (TypeComplete)
return; return;
BaseClasses.Add (baseType); // by default, do not add another vtable pointer for this new base class
int newVirtualMethodCount = baseType.VirtualMethods.Count; AddBase (baseType, false);
}
for (int i = 0; i < newVirtualMethodCount; i++) protected virtual void AddBase (CppTypeInfo baseType, bool addVTablePointer)
VirtualMethods.Insert (BaseVTableSlots + i, baseType.VirtualMethods [i]); {
BaseClasses.Add (baseType);
BaseVTableSlots += newVirtualMethodCount; if (!addVTablePointer) {
VTableDelegateTypes.Skew (newVirtualMethodCount); // If we're not adding a vtptr, then all this base class's virtual methods go in primary vtable
VTableOverrides.Skew (newVirtualMethodCount); // Skew the offsets of this subclass's vmethods to account for the new base vmethods.
int newVirtualMethodCount = baseType.VirtualMethods.Count;
for (int i = 0; i < newVirtualMethodCount; i++)
VirtualMethods.Insert (BaseVTableSlots + i, baseType.VirtualMethods [i]);
BaseVTableSlots += newVirtualMethodCount;
VTableDelegateTypes.Skew (newVirtualMethodCount);
VTableOverrides.Skew (newVirtualMethodCount);
}
field_offset_padding += Marshal.SizeOf (baseType.NativeLayout) + baseType.field_offset_padding; field_offset_padding += baseType.native_size +
(addVTablePointer? baseType.FieldOffsetPadding : baseType.field_offset_padding);
} }
public int CountBases (Func<CppTypeInfo, bool> predicate) public int CountBases (Func<CppTypeInfo, bool> predicate)
@ -90,9 +102,12 @@ namespace Mono.VisualC.Interop {
return count; return count;
} }
// FIXME: Make this thread safe?
public virtual void CompleteType () public virtual void CompleteType ()
{ {
if (TypeComplete) return; if (TypeComplete)
return;
foreach (var baseClass in BaseClasses) foreach (var baseClass in BaseClasses)
baseClass.CompleteType (); baseClass.CompleteType ();

1
Mono.VisualC.Interop/Mono.VisualC.Interop.csproj

@ -57,6 +57,7 @@
<Compile Include="Util\ReflectionHelper.cs" /> <Compile Include="Util\ReflectionHelper.cs" />
<Compile Include="ABI\Impl\MsvcTypeInfo.cs" /> <Compile Include="ABI\Impl\MsvcTypeInfo.cs" />
<Compile Include="Util\MethodSignature.cs" /> <Compile Include="Util\MethodSignature.cs" />
<Compile Include="CppModifiers.cs" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup> <ItemGroup>

28
Mono.VisualC.Interop/Util/IEnumerableTransform.cs

@ -103,12 +103,38 @@ namespace Mono.VisualC.Interop.Util {
yield return additionalValue; yield return additionalValue;
} }
public static bool StartsWith<T> (this IEnumerable<T> current, IEnumerable<T> beginning)
{
IEnumerator<T> currentEnum = current.GetEnumerator ();
IEnumerator<T> beginEnum = beginning.GetEnumerator ();
while (currentEnum.MoveNext ()) {
if (!beginEnum.MoveNext ())
return true;
if (!currentEnum.Current.Equals (beginEnum.Current))
return false;
}
return !beginEnum.MoveNext ();
}
public static IEnumerable<T> Without<T> (this IEnumerable<T> current, T unwantedValue) public static IEnumerable<T> Without<T> (this IEnumerable<T> current, T unwantedValue)
{ {
foreach (var output in current) foreach (var output in current) {
if (!output.Equals (unwantedValue)) if (!output.Equals (unwantedValue))
yield return output; yield return output;
}
}
public static IEnumerable<T> WithoutFirst<T> (this IEnumerable<T> current, T unwantedValue)
{
bool first = true;
foreach (var output in current) {
if (first && output.Equals (unwantedValue))
first = false;
else
yield return output;
}
} }
public static int SequenceHashCode<T> (this IEnumerable<T> sequence) public static int SequenceHashCode<T> (this IEnumerable<T> sequence)

1
QtTest/Main.cs

@ -7,7 +7,6 @@ namespace QtTest {
class MainClass { class MainClass {
public static void Main (string[] args) public static void Main (string[] args)
{ {
//System.Diagnostics.Debug.Assert(false, "Whao");
using (QApplication app = new QApplication ()) { using (QApplication app = new QApplication ()) {
using (QPushButton hello = new QPushButton ("Hello world!"), using (QPushButton hello = new QPushButton ("Hello world!"),
hello2 = new QPushButton ("Another button")) { hello2 = new QPushButton ("Another button")) {

449
generator/Main.cs

@ -10,9 +10,12 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using Mono.VisualC.Interop; using Mono.VisualC.Interop;
using Mono.VisualC.Interop.Util;
using Mono.VisualC.Code; using Mono.VisualC.Code;
using Mono.VisualC.Code.Atoms; using Mono.VisualC.Code.Atoms;
using System.Reflection;
using System.CodeDom;
using System.CodeDom.Compiler; using System.CodeDom.Compiler;
using Microsoft.CSharp; using Microsoft.CSharp;
@ -22,12 +25,33 @@ namespace CPPInterop {
public static readonly string [] genericTypeArgs = new string [] { "T", "U", "V", "W", "X", "Y", "Z" }; public static readonly string [] genericTypeArgs = new string [] { "T", "U", "V", "W", "X", "Y", "Z" };
public string Source { get; set; } public string Source { get; set; }
private CodeUnit currentUnit;
public Dictionary<string, string> Classes; public Dictionary<string, string> Classes;
private CodeUnit enumerations;
public HashSet<string> Enumerations;
private CodeUnit unions;
public HashSet<string> Unions;
public string Dir {get; set;} public string Dir {get; set;}
string templateClass; private string nspace;
string templateStruct; public string Namespace {
string templateInterface; get { return nspace; }
set {
nspace = value;
enumerations.ManagedNamespace = value;
unions.ManagedNamespace = value;
}
}
public string Library {get; set;}
public CodeDomProvider Provider { get; set; }
public CodeGeneratorOptions Options { get; set; }
private Dictionary<string,Property> properties;
public static void Main (string[] args) public static void Main (string[] args)
{ {
@ -36,7 +60,10 @@ namespace CPPInterop {
var p = new OptionSet () { var p = new OptionSet () {
{ "h|?|help", v => help = v != null }, { "h|?|help", v => help = v != null },
{ "f=", v => gen.Source = v }, { "f=", v => gen.Source = v },
{ "o=", v => gen.Dir = v } { "o=", v => gen.Dir = v },
{ "ns=", v => gen.Namespace = v },
{ "lib=", v => gen.Library = v },
{ "lang=", v => gen.Provider = CodeDomProvider.CreateProvider (v) }
}; };
List<string> extra = null; List<string> extra = null;
@ -47,6 +74,11 @@ namespace CPPInterop {
return; return;
} }
if (help) {
p.WriteOptionDescriptions (Console.Error);
return;
}
if (gen.Source == null) { if (gen.Source == null) {
Console.Error.WriteLine ("-f required"); Console.Error.WriteLine ("-f required");
return; return;
@ -56,74 +88,53 @@ namespace CPPInterop {
gen.Dir = "output"; gen.Dir = "output";
Directory.CreateDirectory (gen.Dir); 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 (); gen.Run ();
} }
public Generator () public Generator ()
{ {
Classes = new Dictionary<string, string>(); Classes = new Dictionary<string, string>();
templateClass = File.ReadAllText ("class.template");
templateStruct = File.ReadAllText ("struct.template");
templateInterface = File.ReadAllText ("interface.template");
}
XmlNode find (XmlNode root, XmlAttribute att) Enumerations = new HashSet<string> ();
{ enumerations = new CodeUnit { ManagedNamespace = Namespace };
if (att != null)
return find (root, att.Value);
return null;
}
XmlNode find (XmlNode root, string id) Unions = new HashSet<string> ();
{ unions = new CodeUnit { ManagedNamespace = Namespace };
XmlNode n = root.SelectSingleNode ("/GCC_XML/*[@id='" + id + "']");
//if (n.Name == "Typedef")
// return n;
if (n.Attributes["type"] != null)
return find (root, n.Attributes["type"].Value);
return n;
}
CppType findType (XmlNode root, string id) properties = new Dictionary<string, Property> ();
{
return findType (root, id, new CppType ());
} }
CppType findType (XmlNode root, string id, CppType modifiers) public void Run ()
{ {
XmlNode n = root.SelectSingleNode ("/GCC_XML/*[@id='" + id + "']"); XmlDocument xmldoc = new XmlDocument ();
xmldoc.Load (Source);
switch (n.Name) { //XmlNodeList namespaces = xmldoc.SelectNodes ("/GCC_XML/Namespace[@name != '::' and @name != '' and @name != 'std']");
case "ArrayType": return findType (root, n.Attributes ["type"].Value, modifiers.Modify (CppModifiers.Array));
case "PointerType": return findType (root, n.Attributes ["type"].Value, modifiers.Modify (CppModifiers.Pointer));
case "ReferenceType": return findType (root, n.Attributes ["type"].Value, modifiers.Modify (CppModifiers.Reference));
case "CvQualifiedType": return findType (root, n.Attributes ["type"].Value, modifiers.Modify (n.Attributes ["const"].Value == "1"? CppModifiers.Const : CppModifiers.Volatile));
case "Typedef": return findType (root, n.Attributes ["type"].Value, modifiers);
case "FundamentalType": return modifiers.ApplyTo (new CppType (n.Attributes ["name"].Value));
case "Class": return modifiers.ApplyTo (new CppType (CppTypes.Class, n.Attributes ["name"].Value));
case "Struct": return modifiers.ApplyTo (new CppType (CppTypes.Struct, n.Attributes ["name"].Value));
case "Enumeration": return modifiers.ApplyTo (new CppType (CppTypes.Enum, n.Attributes ["name"].Value));
// FIXME: support function pointers better ProcessClasses (xmldoc);
case "FunctionType": return modifiers.ApplyTo (CppTypes.Void); GenerateStaticLibField ();
}
throw new NotImplementedException ("Unknown type node: " + n.Name); SaveFile (enumerations.WrapperToCodeDom (), "Enums");
SaveFile (unions.WrapperToCodeDom (), "Unions");
} }
public void Run () void ProcessClasses (XmlDocument xmldoc)
{ {
var csharp = new CSharpCodeProvider ();
var options = new CodeGeneratorOptions {
BlankLinesBetweenMembers = false
};
XmlDocument xmldoc = new XmlDocument ();
xmldoc.Load (Source);
XmlNodeList namespaces = xmldoc.SelectNodes ("/GCC_XML/Namespace[@name != '::' and @name != '' and @name != 'std']");
XmlNodeList classes = xmldoc.SelectNodes ("/GCC_XML/Class[not(@incomplete)]"); XmlNodeList classes = xmldoc.SelectNodes ("/GCC_XML/Class[not(@incomplete)]");
foreach (XmlNode clas in classes) { foreach (XmlNode clas in classes) {
var f = xmldoc.SelectSingleNode ("/GCC_XML/File[@id='" + clas.Attributes["file"].Value + "']/@name"); var f = xmldoc.SelectSingleNode ("/GCC_XML/File[@id='" + clas.Attributes["file"].Value + "']/@name");
if (f != null && f.Value.StartsWith ("/")) if (f != null && f.Value.StartsWith ("/"))
@ -149,62 +160,80 @@ namespace CPPInterop {
ras [i] = string.Format ("{0} with {1}", replaceArgs [i].ToString (), letters [i]); ras [i] = string.Format ("{0} with {1}", replaceArgs [i].ToString (), letters [i]);
} }
Console.WriteLine ("Warning: Creating generic type {0}<{1}> from the instantiated template {2} by replacing {3} (very buggy!!!)", baseName, string.Join (",", letters), name, string.Join (", ", ras)); Console.Error.WriteLine ("Warning: Creating generic type {0}<{1}> from the instantiated template {2} by replacing {3} (very buggy!!!)", baseName, string.Join (",", letters), name, string.Join (", ", ras));
name = baseName; name = baseName;
} }
var cu = new CodeUnit { ManagedNamespace = "Qt.Core" }; currentUnit = new CodeUnit { ManagedNamespace = Namespace };
var classAtom = new Class (name) { StaticCppLibrary = "Qt.Libs.QtCore" }; var classAtom = new Class (name) {
if (replaceArgs != null) StaticCppLibrary = string.Format ("{0}.Libs.{1}", Namespace, Library)
};
if (replaceArgs != null) {
for (int i = 0; i < replaceArgs.Length; i++) for (int i = 0; i < replaceArgs.Length; i++)
classAtom.TemplateArguments.Add (genericTypeArgs [i]); classAtom.TemplateArguments.Add (genericTypeArgs [i]);
cu.Atoms.AddLast (classAtom); }
currentUnit.Atoms.AddLast (classAtom);
foreach (XmlNode baseNode in clas.SelectNodes ("Base")) {
classAtom.Bases.Add (new Class.BaseClass {
Name = find (xmldoc.DocumentElement, baseNode.Attributes ["type"]).Attributes ["name"].Value,
Access = baseNode.Attributes ["access"].Value == "public"? Access.Public :
baseNode.Attributes ["access"].Value == "protected"? Access.Protected :
Access.Private,
IsVirtual = baseNode.Attributes ["virtual"].Value == "1"
});
}
string size = clas.Attributes["size"].Value; //string size = clas.Attributes["size"].Value;
string members = clas.Attributes["members"].Value; var members = clas.Attributes["members"].Value.Split (' ').Where (id => !id.Equals (string.Empty));
//StringBuilder str = new StringBuilder(); foreach (string id in members) {
foreach (string id in members.Split(new char[]{' '})) { XmlNode n = xmldoc.SelectSingleNode ("/GCC_XML/*[@id='" + id + "']");
if (id.Equals (String.Empty))
continue; bool ctor = false;
XmlNode n = find (xmldoc.DocumentElement, id); bool dtor = false;
int fieldCount = 0;
switch (n.Name) { switch (n.Name) {
case "Method": case "Constructor":
ctor = true;
break;
case "Destructor":
dtor = true;
break; break;
default: case "Method":
break;
case "Field":
CppType fieldType = findType (xmldoc.DocumentElement, n.Attributes["type"]);
string fname = "field" + fieldCount++;
if (n.Attributes ["name"] != null && n.Attributes ["name"].Value != "")
fname = n.Attributes ["name"].Value;
classAtom.Atoms.AddLast (new Field (fname, fieldType));
continue;
default:
continue; continue;
} }
if (n.Attributes["access"] == null || n.Attributes["access"].Value != "public") if (n.Attributes["access"] == null || n.Attributes["access"].Value != "public" ||
(n.Attributes["overrides"] != null && n.Attributes["overrides"].Value != "" && !dtor) ||
n.Attributes["extern"] == null || n.Attributes["extern"].Value != "1")
continue; continue;
//str.Append ("\t\t\t");
string mname = n.Attributes["name"].Value; string mname = n.Attributes["name"].Value;
CppType retType = findType (xmldoc.DocumentElement, n.Attributes["returns"].Value); CppType retType = findType (xmldoc.DocumentElement, n.Attributes["returns"]);
if (replaceArgs != null) if (replaceArgs != null) {
for (int i = 0; i < replaceArgs.Length; i++) for (int i = 0; i < replaceArgs.Length; i++)
if (replaceArgs [i].ElementTypeName == retType.ElementTypeName) { retType = replaceType (retType, replaceArgs [i], genericTypeArgs [i]);
retType.Subtract (replaceArgs [i]); }
retType.ElementTypeName = genericTypeArgs [i];
}
bool virt = n.Attributes["virtual"] != null && n.Attributes["virtual"].Value == "1";
bool stat = n.Attributes["static"] != null && n.Attributes["static"].Value == "1";
//if (virt)
//str.Append ("[Virtual] ");
//str.Append (rett + " " + mname + " (CppInstancePtr @this");
List<Method.Parameter> args = new List<Method.Parameter> (); var methodAtom = new Method (dtor? "Destruct" : mname) {
var methodAtom = new Method (mname) {
RetType = retType, RetType = retType,
IsVirtual = virt, IsVirtual = n.Attributes["virtual"] != null && n.Attributes["virtual"].Value == "1",
IsStatic = stat, IsStatic = n.Attributes["static"] != null && n.Attributes["static"].Value == "1",
Parameters = args IsConst = n.Attributes["const"] != null && n.Attributes["const"].Value == "1",
IsConstructor = ctor,
IsDestructor = dtor
}; };
int c = 0; int c = 0;
@ -216,50 +245,230 @@ namespace CPPInterop {
argname = arg.Attributes["name"].Value; argname = arg.Attributes["name"].Value;
CppType argtype = findType (xmldoc.DocumentElement, arg.Attributes["type"].Value); CppType argtype = findType (xmldoc.DocumentElement, arg.Attributes["type"].Value);
if (replaceArgs != null) if (replaceArgs != null) {
for (int i = 0; i < replaceArgs.Length; i++) for (int i = 0; i < replaceArgs.Length; i++)
if (replaceArgs [i].ElementTypeName == argtype.ElementTypeName) { argtype = replaceType (argtype, replaceArgs [i], genericTypeArgs [i]);
argtype.Subtract (replaceArgs [i]); }
argtype.ElementTypeName = genericTypeArgs [i];
}
//str.Append (", " + argtype + " " + argname); methodAtom.Parameters.Add (new Method.Parameter { Name = argname, Type = argtype });
args.Add (new Method.Parameter { Name = argname, Type = argtype });
// tee hee // tee hee
c++; c++;
} }
//str.AppendLine (");"); // if it's const, returns a value, and has no parameters, assume it's a property getter (for now?)
if (methodAtom.IsConst && !retType.Equals (CppTypes.Void) && !methodAtom.Parameters.Any ()) {
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);
classAtom.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 a corresponding getter method, then assume it's a property setter
if (mname.ToLower ().StartsWith ("set") && retType.Equals (CppTypes.Void) && methodAtom.Parameters.Count == 1) {
string getterName = "translate(@name, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz') = '" +
mname.Substring (3).TrimStart ('_').ToLower () + "'";
string isMember = "@id = '" + string.Join ("' or @id = '", members.ToArray ()) + "'";
string pname = methodAtom.FormattedName.Substring (3);
Property propertyAtom = null;
// FIXME: This xpath is probably very slow if the class has many members
if (properties.TryGetValue (pname, out propertyAtom) ||
xmldoc.SelectSingleNode (string.Format ("/GCC_XML/Method[{0} and ({1})]", getterName, isMember)) != null) {
if (propertyAtom != null) {
propertyAtom.Setter = methodAtom;
} else {
propertyAtom = new Property (pname) { Setter = methodAtom };
properties.Add (pname, propertyAtom);
classAtom.Atoms.AddLast (propertyAtom);
}
// set the method's arg name to "value" so that the prop setter works right
Method.Parameter valueParam = methodAtom.Parameters [0];
valueParam.Name = "value";
methodAtom.Parameters [0] = valueParam;
continue;
}
}
classAtom.Atoms.AddLast (methodAtom); classAtom.Atoms.AddLast (methodAtom);
} }
Classes.Add (name, sanitize (name) + ".cs"); Classes.Add (name, sanitize (name) + "." + Provider.FileExtension);
SaveFile (currentUnit.WrapperToCodeDom (), name);
FileStream fs = File.Create (Path.Combine (Dir, Classes[name])); }
StreamWriter sw = new StreamWriter(fs); }
/* XmlNode find (XmlNode root, XmlAttribute att)
StringBuilder sb = new StringBuilder(); {
string strstruct = String.Format (templateStruct, name); if (att != null)
string strinterface = String.Format (templateInterface, name, "", str.ToString()); return find (root, att.Value);
sb.Append (string.Format (templateClass, return null;
"Qt.Core", }
name,
"ICppObject", XmlNode find (XmlNode root, string id)
strinterface, {
strstruct, XmlNode n = root.SelectSingleNode ("/GCC_XML/*[@id='" + id + "']");
size)); //if (n.Name == "Typedef")
sw.Write (sb.ToString()); // return n;
*/ if (n.Attributes["type"] != null)
csharp.GenerateCodeFromCompileUnit (cu.WrapperToCodeDom (), sw, options); return find (root, n.Attributes["type"].Value);
return n;
sw.Flush (); }
sw.Close (); CppType findType (XmlNode root, XmlAttribute att)
{
if (att != null)
return findType (root, att.Value);
return CppTypes.Void;
}
CppType findType (XmlNode root, string id)
{
return findType (root, id, new CppType ());
}
CppType findType (XmlNode root, string id, CppType modifiers)
{
XmlNode n = root.SelectSingleNode ("/GCC_XML/*[@id='" + id + "']");
switch (n.Name) {
case "ArrayType": return findType (root, n.Attributes ["type"].Value, modifiers.Modify (CppModifiers.Array));
case "PointerType": return findType (root, n.Attributes ["type"].Value, modifiers.Modify (CppModifiers.Pointer));
case "ReferenceType": return findType (root, n.Attributes ["type"].Value, modifiers.Modify (CppModifiers.Reference));
case "CvQualifiedType":
return findType (root, n.Attributes ["type"].Value,
modifiers.Modify (n.Attributes ["const"] != null && n.Attributes ["const"].Value == "1"? CppModifiers.Const : CppModifiers.Volatile));
case "Typedef": return findType (root, n.Attributes ["type"].Value, modifiers);
case "FundamentalType": return modifiers.ApplyTo (new CppType (n.Attributes ["name"].Value));
case "Class": return modifiers.ApplyTo (new CppType (CppTypes.Class, n.Attributes ["name"].Value));
case "Struct": return modifiers.ApplyTo (new CppType (CppTypes.Struct, n.Attributes ["name"].Value));
case "Union": return modifiers.ApplyTo (ProcessUnion (root, n));
case "Enumeration": return modifiers.ApplyTo (ProcessEnum (n));
// FIXME: support function pointers betters
case "FunctionType": return modifiers.ApplyTo (CppTypes.Void);
}
throw new NotImplementedException ("Unknown type node: " + n.Name);
}
CppType ProcessEnum (XmlNode enm)
{
bool hasName = false;
string ename = "Enum" + Enumerations.Count;
if (enm.Attributes ["name"] != null && enm.Attributes ["name"].Value != "") {
hasName = true;
ename = enm.Attributes ["name"].Value;
}
if (!hasName || !Enumerations.Contains (ename)) {
Enumeration enumAtom = new Enumeration (enm.Attributes ["name"].Value);
foreach (XmlNode v in enm.SelectNodes ("EnumValue"))
enumAtom.Items.Add (new Enumeration.Item { Name = v.Attributes ["name"].Value, Value = Convert.ToInt32 (v.Attributes ["init"].Value) });
if (hasName) // assume it might be shared between classes
enumerations.Atoms.AddLast (enumAtom);
else
currentUnit.Atoms.AddLast (enumAtom);
Enumerations.Add (ename);
}
return new CppType (CppTypes.Enum, ename);
}
CppType ProcessUnion (XmlNode root, XmlNode union)
{
bool hasName = false;
string uname = "Union" + Unions.Count;
if (union.Attributes ["name"] != null && union.Attributes ["name"].Value != "") {
hasName = true;
uname = union.Attributes ["name"].Value;
}
if (!hasName || !Unions.Contains (uname)) {
Union unionAtom = new Union (uname);
foreach (string id in union.Attributes["members"].Value.Split (' ').Where (id => !id.Equals (string.Empty))) {
XmlNode n = root.SelectSingleNode ("/GCC_XML/*[@id = '" + id + "']");
// FIXME: Support union constructors/destructors?
if (n.Name != "Field")
continue;
Field field = new Field (n.Attributes ["name"].Value, findType (root, n.Attributes ["type"]));
unionAtom.Atoms.AddLast (field);
}
if (hasName) // assume it might be shared between classes
unions.Atoms.AddLast (unionAtom);
else
currentUnit.Atoms.AddLast (unionAtom);
Unions.Add (uname);
} }
return new CppType (CppTypes.Union, uname);
}
void GenerateStaticLibField ()
{
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, "Lib_" + Library);
}
void SaveFile (CodeCompileUnit ccu, string baseName)
{
var sw = File.CreateText (Path.Combine (Dir, sanitize (baseName) + "." + Provider.FileExtension));
Provider.GenerateCodeFromCompileUnit (ccu, sw, Options);
sw.Flush ();
sw.Close ();
sw.Dispose ();
} }
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.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;
}
static string sanitize (string name) static string sanitize (string name)
{ {

27
generator/class.template

@ -1,27 +0,0 @@
using System;
using Mono.VisualC.Interop;
namespace {0} {{
public class {1} : {2} {{
// interface
{3}
// struct
{4}
public {1} (IntPtr native) : base (native)
{{
}}
public override int NativeSize {{
get {{ return {5}; }}
}}
public override void Dispose ()
{{
throw new Exception ("This should never be called!");
}}
}}
}}

13
generator/generator.csproj

@ -18,7 +18,7 @@
<DefineConstants>DEBUG</DefineConstants> <DefineConstants>DEBUG</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<Commandlineparameters>-f=/Users/Alex/OpenSource/gccxml/gccxml-build/bin/qobject.xml -o=.</Commandlineparameters> <Commandlineparameters>-f=/Users/Alex/OpenSource/gccxml/gccxml-build/bin/qapplication.xml -o=.</Commandlineparameters>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType> <DebugType>none</DebugType>
@ -46,17 +46,6 @@
<Properties InternalTargetFrameworkVersion="3.5" /> <Properties InternalTargetFrameworkVersion="3.5" />
</MonoDevelop> </MonoDevelop>
</ProjectExtensions> </ProjectExtensions>
<ItemGroup>
<None Include="class.template">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="interface.template">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="struct.template">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Mono.VisualC.Code\Mono.VisualC.Code.csproj"> <ProjectReference Include="..\Mono.VisualC.Code\Mono.VisualC.Code.csproj">
<Project>{A22BF9D9-BBCB-4462-BE08-0F4D5280B180}</Project> <Project>{A22BF9D9-BBCB-4462-BE08-0F4D5280B180}</Project>

3
generator/interface.template

@ -1,3 +0,0 @@
public interface I{0} : ICppClassOverridable<{0}> {1} {{
{2}
}}

3
generator/struct.template

@ -1,3 +0,0 @@
private struct _{0} {{
public IntPtr d_ptr;
}}
Loading…
Cancel
Save