Browse Source

Added validation mode to generator that will confirm that bindings compile and that names are correctly mangled. Fixes to generator to fix compile errors with generated bindings, however they do not compile out of the box as yet.

git-svn-id: https://mono-soc-2010.googlecode.com/svn/trunk/cppinterop@123 a470b8cb-0e6f-1642-1b45-71e107334c4b
pull/1/head
alexander.corrado 15 years ago
parent
commit
3b0a3f418b
  1. 26
      Mono.VisualC.Code/Atoms/Class.cs
  2. 16
      Mono.VisualC.Code/Atoms/Field.cs
  3. 70
      Mono.VisualC.Code/Atoms/Method.cs
  4. 14
      Mono.VisualC.Code/CodeAtom.cs
  5. 28
      Mono.VisualC.Code/CodeDomExtensions.cs
  6. 5
      Mono.VisualC.Code/CodeUnit.cs
  7. 1
      Mono.VisualC.Code/Mono.VisualC.Code.csproj
  8. 9
      Mono.VisualC.Code/NameTypePair.cs
  9. 23
      Mono.VisualC.Interop/Attributes.cs
  10. 4
      Mono.VisualC.Interop/CppType.cs
  11. 334
      generator/Main.cs
  12. 37
      generator/MethodSignature.cs
  13. 1
      generator/generator.csproj

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

@ -45,7 +45,7 @@ namespace Mono.VisualC.Code.Atoms { @@ -45,7 +45,7 @@ namespace Mono.VisualC.Code.Atoms {
return wrapper;
}
private CodeTypeDeclaration CreateWrapperClass ()
public CodeTypeDeclaration CreateWrapperClass ()
{
var wrapper = new CodeTypeDeclaration (Name) { TypeAttributes = TypeAttributes.Public };
foreach (var arg in TemplateArguments)
@ -102,18 +102,25 @@ namespace Mono.VisualC.Code.Atoms { @@ -102,18 +102,25 @@ namespace Mono.VisualC.Code.Atoms {
atom.Visit (wrapper);
}
if (dispose == null)
wrapper.Members.Add (CreateDestructorlessDispose ());
else if (hasOverrides)
if (dispose == null) {
dispose = CreateDestructorlessDispose ();
wrapper.Members.Add (dispose);
}
if (hasOverrides)
dispose.Attributes |= MemberAttributes.Override;
return wrapper;
}
private CodeTypeDeclaration CreateInterface (CodeTypeDeclaration wrapper)
public CodeTypeDeclaration CreateInterface ()
{
return CreateInterface (null);
}
public CodeTypeDeclaration CreateInterface (CodeTypeDeclaration wrapper)
{
var iface = new CodeTypeDeclaration ("I" + Name) {
TypeAttributes = TypeAttributes.Interface | TypeAttributes.NestedPublic,
TypeAttributes = TypeAttributes.Interface | (wrapper != null? TypeAttributes.NestedPublic : TypeAttributes.Public),
Attributes = MemberAttributes.Public,
IsInterface = true
};
@ -121,7 +128,10 @@ namespace Mono.VisualC.Code.Atoms { @@ -121,7 +128,10 @@ namespace Mono.VisualC.Code.Atoms {
foreach (var arg in TemplateArguments)
iface.TypeParameters.Add (arg);
iface.BaseTypes.Add (new CodeTypeReference (typeof (ICppClassOverridable<>).Name, wrapper.TypeReference ()));
if (wrapper != null)
iface.BaseTypes.Add (new CodeTypeReference (typeof (ICppClassOverridable<>).Name, wrapper.TypeReference ()));
else
iface.BaseTypes.Add (new CodeTypeReference (typeof (ICppClass).Name));
foreach (var atom in Atoms)
atom.Visit (iface);
@ -129,7 +139,7 @@ namespace Mono.VisualC.Code.Atoms { @@ -129,7 +139,7 @@ namespace Mono.VisualC.Code.Atoms {
return iface;
}
private CodeTypeDeclaration CreateNativeLayout ()
public CodeTypeDeclaration CreateNativeLayout ()
{
var native = new CodeTypeDeclaration ("_" + Name) {
TypeAttributes = TypeAttributes.NestedPrivate | TypeAttributes.SequentialLayout,

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

@ -36,15 +36,21 @@ namespace Mono.VisualC.Code.Atoms { @@ -36,15 +36,21 @@ namespace Mono.VisualC.Code.Atoms {
return field;
}
// FIXME: Handle fixed size arrays? Can't really see a good way to do that yet.
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));
if (Type.Modifiers.Count > 0) {
CppModifiers lastModifier = Type.Modifiers [Type.Modifiers.Count - 1];
if (lastModifier == CppModifiers.Pointer || lastModifier == CppModifiers.Reference)
return new CodeTypeReference (typeof (IntPtr));
}
if (Type.ElementType == CppTypes.Enum || Type.ElementType == CppTypes.Union)
return new CodeTypeReference (Type.ElementTypeName);
// FIXME: Handle arrays (fixed size?)
if (Type.ElementType == CppTypes.Typename)
return new CodeTypeReference (Type.ElementTypeName, CodeTypeReferenceOptions.GenericTypeParameter);
Type managedType = Type.ToManagedType ();
if (managedType != null)

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

@ -6,14 +6,11 @@ using System.Collections.Generic; @@ -6,14 +6,11 @@ using System.Collections.Generic;
using System.CodeDom;
using Mono.VisualC.Interop;
using Mono.VisualC.Interop.ABI;
namespace Mono.VisualC.Code.Atoms {
public class Method : CodeContainer {
public struct Parameter {
public string Name;
public CppType Type;
}
public string Name { get; set; }
public Access Access { get; set; }
@ -24,23 +21,55 @@ namespace Mono.VisualC.Code.Atoms { @@ -24,23 +21,55 @@ namespace Mono.VisualC.Code.Atoms {
public bool IsDestructor { get; set; }
public CppType RetType { get; set; }
public IList<Parameter> Parameters { get; set; }
public IList<NameTypePair<CppType>> Parameters { get; set; }
// for testing:
// FIXME: make this Nullable, auto implemented property and remove bool field once this won't cause gmcs to crash
public NameTypePair<Type> Mangled {
get {
if (!hasMangledInfo) throw new InvalidOperationException ("No mangle info present.");
return mangled;
}
set {
mangled = value;
hasMangledInfo = true;
}
}
private NameTypePair<Type> mangled;
private bool hasMangledInfo = false;
public Method (string name)
{
Name = name;
Parameters = new List<Parameter> ();
Parameters = new List<NameTypePair<CppType>> ();
}
internal protected override object InsideCodeTypeDeclaration (CodeTypeDeclaration decl)
{
if (decl.IsClass) {
// FIXME: add commented methods to wrappers too? for now, I say let's reduce code clutter.
if (CommentedOut)
return null;
var method = CreateWrapperMethod ();
decl.Members.Add (method);
return method;
} else if (decl.IsInterface)
decl.Members.Add (CreateInterfaceMethod ());
} else if (decl.IsInterface) {
CodeTypeMember member;
if (CommentedOut) {
member = new CodeSnippetTypeMember ();
member.Comments.Add (new CodeCommentStatement (Comment));
member.Comments.Add (new CodeCommentStatement (CreateInterfaceMethod ().CommentOut (current_code_provider)));
} else
member = CreateInterfaceMethod ();
decl.Members.Add (member);
}
return null;
}
@ -52,7 +81,7 @@ namespace Mono.VisualC.Code.Atoms { @@ -52,7 +81,7 @@ namespace Mono.VisualC.Code.Atoms {
arguments.Add (new CodeFieldReferenceExpression (new CodeThisReferenceExpression (), "Native"));
foreach (var param in Parameters) {
// FIXME: handle typenames
// FIXME: handle typenames better
if (param.Type.ElementType != CppTypes.Typename) {
Type managedType = param.Type.ToManagedType ();
if (managedType != null && managedType.IsByRef) {
@ -93,7 +122,13 @@ namespace Mono.VisualC.Code.Atoms { @@ -93,7 +122,13 @@ namespace Mono.VisualC.Code.Atoms {
else
method.Parameters.Add (new CodeParameterDeclarationExpression (typeof (CppInstancePtr).Name, "this"));
AddParameters (method, true);
if (hasMangledInfo)
method.CustomAttributes.Add (new CodeAttributeDeclaration ("ValidateBindings",
new CodeAttributeArgument (new CodePrimitiveExpression (Mangled.Name)),
new CodeAttributeArgument ("Abi", new CodeTypeOfExpression (Mangled.Type))));
foreach (var param in GetParameterDeclarations (true))
method.Parameters.Add (param);
return method;
}
@ -128,7 +163,9 @@ namespace Mono.VisualC.Code.Atoms { @@ -128,7 +163,9 @@ namespace Mono.VisualC.Code.Atoms {
else if (IsVirtual && !IsDestructor)
method.CustomAttributes.Add (new CodeAttributeDeclaration ("OverrideNative"));
AddParameters (method, false);
foreach (var param in GetParameterDeclarations (false))
method.Parameters.Add (param);
return method;
}
@ -152,7 +189,12 @@ namespace Mono.VisualC.Code.Atoms { @@ -152,7 +189,12 @@ namespace Mono.VisualC.Code.Atoms {
}
}
private void AddParameters (CodeMemberMethod method, bool includeMangleAttribute)
public IEnumerable<CodeParameterDeclarationExpression> GetParameterDeclarations ()
{
return GetParameterDeclarations (false);
}
private IEnumerable<CodeParameterDeclarationExpression> GetParameterDeclarations (bool includeMangleAttribute)
{
foreach (var param in Parameters) {
CodeParameterDeclarationExpression paramDecl;
@ -174,7 +216,7 @@ namespace Mono.VisualC.Code.Atoms { @@ -174,7 +216,7 @@ namespace Mono.VisualC.Code.Atoms {
if (includeMangleAttribute && !IsVirtual && !paramStr.Equals (string.Empty))
paramDecl.CustomAttributes.Add (new CodeAttributeDeclaration ("MangleAs", new CodeAttributeArgument (new CodePrimitiveExpression (paramStr))));
method.Parameters.Add (paramDecl);
yield return paramDecl;
}
}

14
Mono.VisualC.Code/CodeAtom.cs

@ -4,13 +4,25 @@ using System.IO; @@ -4,13 +4,25 @@ using System.IO;
using System.Collections.Generic;
using System.CodeDom;
using System.CodeDom.Compiler;
namespace Mono.VisualC.Code {
public abstract class CodeAtom {
public string Comment { get; set; }
public bool CommentedOut { get; set; }
protected CodeDomProvider current_code_provider;
internal protected virtual void Visit (object obj)
{
Visit (obj, current_code_provider);
}
internal protected virtual void Visit (object obj, CodeDomProvider provider)
{
current_code_provider = provider;
object result = obj;
while (result != null) {
@ -21,6 +33,8 @@ namespace Mono.VisualC.Code { @@ -21,6 +33,8 @@ namespace Mono.VisualC.Code {
if (result is CodeStatementCollection) { result = InsideCodeStatementCollection (result as CodeStatementCollection); continue; }
break;
}
current_code_provider = null;
}
internal protected virtual object InsideCodeCompileUnit (CodeCompileUnit ccu)

28
Mono.VisualC.Code/CodeDomExtensions.cs

@ -1,14 +1,42 @@ @@ -1,14 +1,42 @@
using System;
using System.IO;
using System.Linq;
using System.Text;
using System.CodeDom;
using System.CodeDom.Compiler;
using Mono.VisualC.Interop;
namespace Mono.VisualC.Code {
internal delegate void CodeGenMethod<T> (T codeObject, TextWriter writer, CodeGeneratorOptions cgo);
public static class CodeDomExtensions {
public static CodeComment CommentOut (this CodeTypeMember code, CodeDomProvider provider)
{
// FIXME: Not implemented ini mono
//return CommentOut (provider.GenerateCodeFromMember, code);
return new CodeComment ();
}
public static CodeComment CommentOut (this CodeStatement code, CodeDomProvider provider)
{
return CommentOut (provider.GenerateCodeFromStatement, code);
}
public static CodeComment CommentOut (this CodeExpression code, CodeDomProvider provider)
{
return CommentOut (provider.GenerateCodeFromExpression, code);
}
private static CodeComment CommentOut<T> (CodeGenMethod<T> method, T codeObject)
{
StringWriter output = new StringWriter ();
CodeGeneratorOptions opts = new CodeGeneratorOptions ();
method (codeObject, output, opts);
return new CodeComment (output.ToString ());
}
public static CodeTypeReference TypeReference (this CodeTypeDeclaration ctd)
{
return new CodeTypeReference (ctd.Name, ctd.TypeParameterReferences ());

5
Mono.VisualC.Code/CodeUnit.cs

@ -4,6 +4,7 @@ using System.IO; @@ -4,6 +4,7 @@ using System.IO;
using System.Collections.Generic;
using System.CodeDom;
using System.CodeDom.Compiler;
namespace Mono.VisualC.Code {
public class CodeUnit : CodeContainer {
@ -14,10 +15,10 @@ namespace Mono.VisualC.Code { @@ -14,10 +15,10 @@ namespace Mono.VisualC.Code {
{
}
public virtual CodeCompileUnit WrapperToCodeDom ()
public virtual CodeCompileUnit WrapperToCodeDom (CodeDomProvider provider)
{
CodeCompileUnit ccu = new CodeCompileUnit ();
Visit (ccu);
Visit (ccu, provider);
return ccu;
}

1
Mono.VisualC.Code/Mono.VisualC.Code.csproj

@ -46,6 +46,7 @@ @@ -46,6 +46,7 @@
<Compile Include="Atoms\Property.cs" />
<Compile Include="Atoms\Field.cs" />
<Compile Include="Atoms\Union.cs" />
<Compile Include="NameTypePair.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>

9
Mono.VisualC.Code/NameTypePair.cs

@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
using System;
namespace Mono.VisualC.Code {
public struct NameTypePair<TType> {
public string Name;
public TType Type;
}
}

23
Mono.VisualC.Interop/Attributes.cs

@ -10,6 +10,7 @@ @@ -10,6 +10,7 @@
using System;
using System.Linq;
using System.Reflection;
using System.Diagnostics;
namespace Mono.VisualC.Interop {
@ -29,6 +30,7 @@ namespace Mono.VisualC.Interop { @@ -29,6 +30,7 @@ namespace Mono.VisualC.Interop {
public class StaticAttribute : Attribute {}
// used for the const "this" - for example: int value () const;
// use MangleAsAttribute for const parameters
[AttributeUsage (AttributeTargets.Method)]
public class ConstAttribute : Attribute {}
@ -56,10 +58,25 @@ namespace Mono.VisualC.Interop { @@ -56,10 +58,25 @@ namespace Mono.VisualC.Interop {
this.MangleType = new CppType (cppTypeSpec);
}
}
// for testing:
[AttributeUsage (AttributeTargets.Method)]
public class ValidateBindingsAttribute : Attribute {
public string MangledName { get; set; }
public Type Abi { get; set; }
public ValidateBindingsAttribute (string mangledName)
{
MangledName = mangledName;
}
}
#endregion
#region Wrapper method attributes
[AttributeUsage (AttributeTargets.Method)]
public class OverrideNativeAttribute : Attribute {}
#endregion
}
namespace Mono.VisualC.Interop.ABI {
@ -105,6 +122,12 @@ using Mono.VisualC.Interop; @@ -105,6 +122,12 @@ using Mono.VisualC.Interop;
return mangleType;
}
[Conditional ("VALIDATE")]
public virtual void ValidateBindings (MemberInfo member)
{
throw new NotImplementedException ();
}
}
}

4
Mono.VisualC.Interop/CppType.cs

@ -31,6 +31,7 @@ namespace Mono.VisualC.Interop { @@ -31,6 +31,7 @@ namespace Mono.VisualC.Interop {
Int,
Float,
Double,
WChar_T,
// for template type parameters
Typename
}
@ -51,7 +52,8 @@ namespace Mono.VisualC.Interop { @@ -51,7 +52,8 @@ namespace Mono.VisualC.Interop {
(t) => t.ElementType == CppTypes.Void && t.Modifiers.Contains (CppModifiers.Pointer)? typeof (IntPtr) : null,
// single pointer to char gets string
(t) => t.ElementType == CppTypes.Char && t.Modifiers.Count (m => m == CppModifiers.Pointer) == 1? typeof (string) : null,
// same with wchar_t (needs marshaling attribute though!)
(t) => (t.ElementType == CppTypes.Char || t.ElementType == CppTypes.WChar_T) && t.Modifiers.Count (m => m == CppModifiers.Pointer) == 1? typeof (string) : null,
// pointer to pointer to char gets string[]
(t) => t.ElementType == CppTypes.Char && t.Modifiers.Count (m => m == CppModifiers.Pointer) == 2? typeof (string).MakeArrayType () : null,

334
generator/Main.cs

@ -10,6 +10,7 @@ using System.Collections.Generic; @@ -10,6 +10,7 @@ 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;
@ -25,17 +26,9 @@ namespace CPPInterop { @@ -25,17 +26,9 @@ namespace CPPInterop {
public static readonly string [] genericTypeArgs = new string [] { "T", "U", "V", "W", "X", "Y", "Z" };
public string Source { get; set; }
private CodeUnit currentUnit;
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 bool ShouldValidate { get; set; }
public string Library {get; set;}
private string nspace;
public string Namespace {
@ -47,18 +40,28 @@ namespace CPPInterop { @@ -47,18 +40,28 @@ namespace CPPInterop {
}
}
public string Library {get; set;}
public Dictionary<string, string> Classes;
public HashSet<string> Enumerations;
public HashSet<string> Unions;
public Dictionary<string,CodeTypeDeclaration> UnknownTypes;
public CodeDomProvider Provider { get; set; }
public CodeGeneratorOptions Options { get; set; }
private CodeUnit currentUnit;
private CodeUnit enumerations;
private CodeUnit unions;
private Dictionary<string,Property> properties;
private HashSet<string> fileList;
public static void Main (string[] args)
{
bool help = false;
Generator gen = new Generator ();
var p = new OptionSet () {
{ "h|?|help", v => help = v != null },
{ "validate", v => gen.ShouldValidate = v != null },
{ "f=", v => gen.Source = v },
{ "o=", v => gen.Dir = v },
{ "ns=", v => gen.Namespace = v },
@ -109,27 +112,41 @@ namespace CPPInterop { @@ -109,27 +112,41 @@ namespace CPPInterop {
public Generator ()
{
Classes = new Dictionary<string, string>();
UnknownTypes = new Dictionary<string,CodeTypeDeclaration> ();
Enumerations = new HashSet<string> ();
enumerations = new CodeUnit { ManagedNamespace = Namespace };
Unions = new HashSet<string> ();
unions = 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...");
XmlDocument xmldoc = new XmlDocument ();
xmldoc.Load (Source);
// FIXME: Support namespaces!!!
//XmlNodeList namespaces = xmldoc.SelectNodes ("/GCC_XML/Namespace[@name != '::' and @name != '' and @name != 'std']");
ProcessClasses (xmldoc);
GenerateStaticLibField ();
SaveFile (enumerations.WrapperToCodeDom (), "Enums");
SaveFile (unions.WrapperToCodeDom (), "Unions");
if (enumerations.Atoms.Any ())
SaveFile (enumerations.WrapperToCodeDom (Provider), "Enums");
if (unions.Atoms.Any ())
SaveFile (unions.WrapperToCodeDom (Provider), "Unions");
if (ShouldValidate) {
GenerateUnknownTypeStubs ();
Validate ();
//File.Delete (fileList.Where (f => f.StartsWith ("UnknownTypes")).Single ());
}
}
void ProcessClasses (XmlDocument xmldoc)
@ -172,7 +189,14 @@ namespace CPPInterop { @@ -172,7 +189,14 @@ namespace CPPInterop {
for (int i = 0; i < replaceArgs.Length; i++)
classAtom.TemplateArguments.Add (genericTypeArgs [i]);
}
currentUnit.Atoms.AddLast (classAtom);
Classes.Add (name, fname (name));
CppType currentType = new CppType (CppTypes.Class, name);;
if (replaceArgs != null)
currentType.Modify (new CppModifiers.TemplateModifier (replaceArgs));
CheckType (currentType);
foreach (XmlNode baseNode in clas.SelectNodes ("Base")) {
classAtom.Bases.Add (new Class.BaseClass {
@ -185,7 +209,8 @@ namespace CPPInterop { @@ -185,7 +209,8 @@ namespace CPPInterop {
}
//string size = clas.Attributes["size"].Value;
var members = clas.Attributes["members"].Value.Split (' ').Where (id => !id.Equals (string.Empty));
var members = clas.Attributes["members"].Value.Split (' ').Where (id => !id.Equals (string.Empty)).ToArray ();
Dictionary<MethodSignature,string> methods = new Dictionary<MethodSignature, string> ();
foreach (string id in members) {
XmlNode n = xmldoc.SelectSingleNode ("/GCC_XML/*[@id='" + id + "']");
@ -205,23 +230,25 @@ namespace CPPInterop { @@ -205,23 +230,25 @@ namespace CPPInterop {
break;
case "Field":
CppType fieldType = findType (xmldoc.DocumentElement, n.Attributes["type"]);
string fname = "field" + fieldCount++;
string fieldName = "field" + fieldCount++;
if (n.Attributes ["name"] != null && n.Attributes ["name"].Value != "")
fname = n.Attributes ["name"].Value;
classAtom.Atoms.AddLast (new Field (fname, fieldType));
fieldName = n.Attributes ["name"].Value;
classAtom.Atoms.AddLast (new Field (fieldName, fieldType));
continue;
default:
continue;
}
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")
// Now we're processing a method...
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;
string mname = n.Attributes["name"].Value;
string mname = n.Attributes ["name"].Value;
CppType retType = findType (xmldoc.DocumentElement, n.Attributes["returns"]);
CppType retType = findType (xmldoc.DocumentElement, n.Attributes ["returns"]);
if (replaceArgs != null) {
for (int i = 0; i < replaceArgs.Length; i++)
retType = replaceType (retType, replaceArgs [i], genericTypeArgs [i]);
@ -229,35 +256,63 @@ namespace CPPInterop { @@ -229,35 +256,63 @@ namespace CPPInterop {
var methodAtom = new Method (dtor? "Destruct" : mname) {
RetType = retType,
IsVirtual = n.Attributes["virtual"] != null && n.Attributes["virtual"].Value == "1",
IsStatic = n.Attributes["static"] != null && n.Attributes["static"].Value == "1",
IsConst = n.Attributes["const"] != null && n.Attributes["const"].Value == "1",
IsVirtual = n.Attributes ["virtual"] != null && n.Attributes ["virtual"].Value == "1",
IsStatic = n.Attributes ["static"] != null && n.Attributes ["static"].Value == "1",
IsConst = n.Attributes ["const"] != null && n.Attributes ["const"].Value == "1",
IsConstructor = ctor,
IsDestructor = dtor
};
if (ShouldValidate)
methodAtom.Mangled = new NameTypePair<Type> { Name = n.Attributes ["mangled"].Value, Type = typeof (ItaniumAbi) };
XmlNodeList argNodes = n.SelectNodes ("Argument");
CppType [] argTypes = new CppType [argNodes.Count];
int c = 0;
foreach (XmlNode arg in n.SelectNodes ("Argument")) {
foreach (XmlNode arg in argNodes) {
string argname;
if (arg.Attributes["name"] == null)
if (arg.Attributes ["name"] == null)
argname = "arg" + c;
else
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) {
for (int i = 0; i < replaceArgs.Length; i++)
argtype = replaceType (argtype, replaceArgs [i], genericTypeArgs [i]);
}
methodAtom.Parameters.Add (new Method.Parameter { Name = argname, Type = argtype });
methodAtom.Parameters.Add (new NameTypePair<CppType> { Name = argname, Type = argtype });
argTypes [c] = argtype;
// tee hee
c++;
}
// 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 ()) {
// Try to filter out duplicate methods
MethodSignature sig = new MethodSignature { Name = methodAtom.FormattedName, Arguments = argTypes };
string conflictingSig;
if (methods.TryGetValue (sig, out conflictingSig)) {
// FIXME: add comment to explain why it's commented out
string demangled = n.Attributes ["demangled"].Value;
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, n.Attributes ["demangled"].Value);
// Record unknown types in parameters and return type
CheckType (methodAtom.RetType);
foreach (var arg in methodAtom.Parameters)
CheckType (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 () &&
findMethod (xmldoc.DocumentElement, members, "@id != '" + id + "' and @name = '" + mname + "'") == null) {
var pname = methodAtom.FormattedName;
Property propertyAtom;
@ -273,17 +328,17 @@ namespace CPPInterop { @@ -273,17 +328,17 @@ namespace CPPInterop {
}
// 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) {
// and there is no other method with the same name...
if (mname.ToLower ().StartsWith ("set") && retType.Equals (CppTypes.Void) && methodAtom.Parameters.Count == 1 &&
findMethod (xmldoc.DocumentElement, members, "@id != '" + id + "' and @name = '" + mname + "'") == null) {
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) {
// ...AND there is a corresponding getter method, then assume it's a property setter
if (properties.TryGetValue (pname, out propertyAtom) || findMethod (xmldoc.DocumentElement, members, getterName) != null) {
if (propertyAtom != null) {
propertyAtom.Setter = methodAtom;
@ -294,7 +349,7 @@ namespace CPPInterop { @@ -294,7 +349,7 @@ namespace CPPInterop {
}
// set the method's arg name to "value" so that the prop setter works right
Method.Parameter valueParam = methodAtom.Parameters [0];
var valueParam = methodAtom.Parameters [0];
valueParam.Name = "value";
methodAtom.Parameters [0] = valueParam;
@ -305,66 +360,33 @@ namespace CPPInterop { @@ -305,66 +360,33 @@ namespace CPPInterop {
classAtom.Atoms.AddLast (methodAtom);
}
Classes.Add (name, sanitize (name) + "." + Provider.FileExtension);
SaveFile (currentUnit.WrapperToCodeDom (), name);
}
}
XmlNode find (XmlNode root, XmlAttribute att)
{
if (att != null)
return find (root, att.Value);
return null;
}
XmlNode find (XmlNode root, string id)
{
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, 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 ());
SaveFile (currentUnit.WrapperToCodeDom (Provider), name);
}
}
CppType findType (XmlNode root, string id, CppType modifiers)
void Validate ()
{
XmlNode n = root.SelectSingleNode ("/GCC_XML/*[@id='" + id + "']");
Console.WriteLine ("Validating bindings...");
string name = "unknown";
if (n.Attributes ["name"] != null)
name = n.Attributes ["name"].Value;
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));
var compileParams = new CompilerParameters {
GenerateInMemory = true,
TreatWarningsAsErrors = false
};
compileParams.ReferencedAssemblies.Add (typeof (CppLibrary).Assembly.CodeBase);
case "Typedef": return findType (root, n.Attributes ["type"].Value, modifiers);
CompilerResults results = Provider.CompileAssemblyFromFile (compileParams, fileList.ToArray ());
case "FundamentalType": return modifiers.ApplyTo (new CppType (name));
case "Class": return modifiers.ApplyTo (new CppType (CppTypes.Class, name));
case "Struct": return modifiers.ApplyTo (new CppType (CppTypes.Struct, name));
case "Union": return modifiers.ApplyTo (ProcessUnion (root, n));
case "Enumeration": return modifiers.ApplyTo (ProcessEnum (n));
if (results.Errors.Count > 0) {
foreach (CompilerError error in results.Errors)
Console.Error.WriteLine ("{0}({1},{2}): error {3}: {4}", error.FileName, error.Line, error.Column, error.ErrorNumber, error.ErrorText);
// FIXME: support function pointers betters
case "FunctionType": return modifiers.ApplyTo (CppTypes.Void);
Console.Error.WriteLine ("Validation failed with {0} compilation errors.", results.Errors.Count);
}
throw new NotImplementedException ("Unknown type node: " + n.Name);
//Type [] types = validationAssembly.GetExportedTypes ();
// do stuff...
}
CppType ProcessEnum (XmlNode enm)
@ -431,6 +453,10 @@ namespace CPPInterop { @@ -431,6 +453,10 @@ namespace CPPInterop {
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") {
@ -446,16 +472,41 @@ namespace CPPInterop { @@ -446,16 +472,41 @@ namespace CPPInterop {
ns.Types.Add (cls);
ccu.Namespaces.Add (ns);
SaveFile (ccu, "Lib_" + Library);
SaveFile (ccu, name);
}
void GenerateUnknownTypeStubs ()
{
var ccu = new CodeCompileUnit ();
var ns = new CodeNamespace (Namespace);
foreach (var type in UnknownTypes)
ns.Types.Add (type.Value);
ccu.Namespaces.Add (ns);
SaveFile (ccu, "UnknownTypes");
}
void SaveFile (CodeCompileUnit ccu, string baseName)
{
var sw = File.CreateText (Path.Combine (Dir, sanitize (baseName) + "." + Provider.FileExtension));
string name = Path.Combine (Dir, fname (baseName));
if (File.Exists (name) && fileList.Contains (name))
return;
if (File.Exists (name) && !fileList.Contains (name)) {
int i = 1;
while (File.Exists (Path.Combine (Dir, fname (baseName + i))))
i++;
name = fname (baseName + i);
}
var sw = File.CreateText (Path.Combine (Dir, 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)
@ -473,9 +524,100 @@ namespace CPPInterop { @@ -473,9 +524,100 @@ namespace CPPInterop {
return inType;
}
static string sanitize (string name)
// FIXME: Do something trickier than just throw ElementTypeName in here?
void CheckType (CppType cpptype)
{
string type = cpptype.ElementTypeName;
if (type == null) return;
bool typeFound = Classes.ContainsKey (type) || Enumerations.Contains (type) || Unions.Contains (type);
bool alreadyUnknown = UnknownTypes.ContainsKey (type);
if (!typeFound && !alreadyUnknown) {
var ctd = new CodeTypeDeclaration (type) {
TypeAttributes = TypeAttributes.Public,
IsClass = true,
IsPartial = true
};
if (cpptype.Modifiers.Contains (CppModifiers.Template)) {
var template = cpptype.Modifiers.OfType<CppModifiers.TemplateModifier> ().Single ();
for (int i = 0; i < template.Types.Length; i++)
ctd.TypeParameters.Add (genericTypeArgs [i]);
}
UnknownTypes.Add (type, ctd);
} else if (typeFound && alreadyUnknown)
UnknownTypes.Remove (type);
}
static XmlNode find (XmlNode root, XmlAttribute att)
{
if (att != null)
return find (root, att.Value);
return null;
}
static XmlNode find (XmlNode root, string id)
{
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;
}
static XmlNode findMethod (XmlNode root, string [] members, string predicate)
{
string isMember = "@id = '" + string.Join ("' or @id = '", members) + "'";
return root.SelectSingleNode (string.Format ("/GCC_XML/Method[({0}) and ({1})]", predicate, isMember));
}
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 + "']");
string name = "unknown";
if (n.Attributes ["name"] != null)
name = n.Attributes ["name"].Value;
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 (name));
case "Class": return modifiers.ApplyTo (new CppType (CppTypes.Class, name));
case "Struct": return modifiers.ApplyTo (new CppType (CppTypes.Struct, name));
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);
}
string fname (string name)
{
return name.Replace ("<", "_").Replace (">", "_").Replace(":", "_").Replace("*", "_").Replace (",", "_").Replace(" ", "_");
return name.Replace ("<", "_").Replace (">", "_").Replace(":", "_").Replace("*", "_").Replace (",", "_").Replace(" ", "_") + "." + Provider.FileExtension;
}
}
}

37
generator/MethodSignature.cs

@ -0,0 +1,37 @@ @@ -0,0 +1,37 @@
using System;
using System.Linq;
using Mono.VisualC.Interop;
using Mono.VisualC.Interop.Util;
namespace CPPInterop {
// This is the best I could come up with to prevent duplicate managed
// signatures. The problem is, most of the types don't exist yet.
public struct MethodSignature {
public string Name;
public CppType [] Arguments;
public override bool Equals (object obj)
{
if (obj == null)
return false;
if (obj.GetType () != typeof(MethodSignature))
return false;
MethodSignature other = (MethodSignature)obj;
return Name == other.Name &&
Arguments != null? Arguments.SequenceEqual (other.Arguments) :
other.Arguments == null;
}
public override int GetHashCode ()
{
unchecked {
return (Name != null? Name.GetHashCode () : 0) ^
(Arguments != null? Arguments.SequenceHashCode () : 0);
}
}
}
}

1
generator/generator.csproj

@ -30,6 +30,7 @@ @@ -30,6 +30,7 @@
<ItemGroup>
<Compile Include="Main.cs" />
<Compile Include="Options.cs" />
<Compile Include="MethodSignature.cs" />
</ItemGroup>
<ItemGroup>
<Reference Include="System">

Loading…
Cancel
Save