Generator bug fixes. Now fully compiles bindings from qapplication.xml and will start testing mangled names against GCC-XML output before crashing. Preliminary support for C++ namespaces.
git-svn-id: https://mono-soc-2010.googlecode.com/svn/trunk/cppinterop@132 a470b8cb-0e6f-1642-1b45-71e107334c4b
This commit is contained in:
Родитель
3b0a3f418b
Коммит
1a27eb3119
|
@ -24,7 +24,6 @@ namespace Mono.VisualC.Code.Atoms {
|
|||
public bool IsVirtual;
|
||||
}
|
||||
|
||||
public string Name { get; set; }
|
||||
public string StaticCppLibrary { get; set; }
|
||||
public Definition DefinedAs { get; set; }
|
||||
|
||||
|
@ -40,17 +39,33 @@ namespace Mono.VisualC.Code.Atoms {
|
|||
|
||||
internal protected override object InsideCodeNamespace (CodeNamespace ns)
|
||||
{
|
||||
var wrapper = CreateWrapperClass ();
|
||||
ns.Types.Add (wrapper);
|
||||
return wrapper;
|
||||
ns.Types.Add (CreateWrapperClass ());
|
||||
return null;
|
||||
}
|
||||
|
||||
internal protected override object InsideCodeTypeDeclaration (CodeTypeDeclaration decl)
|
||||
{
|
||||
if (!decl.IsClass)
|
||||
return null;
|
||||
|
||||
decl.Members.Add (CreateWrapperClass ());
|
||||
return null;
|
||||
}
|
||||
|
||||
public CodeTypeDeclaration CreateWrapperClass ()
|
||||
{
|
||||
var wrapper = new CodeTypeDeclaration (Name) { TypeAttributes = TypeAttributes.Public };
|
||||
var wrapper = new CodeTypeDeclaration (Name) {
|
||||
Attributes = MemberAttributes.Public,
|
||||
TypeAttributes = TypeAttributes.Public
|
||||
};
|
||||
foreach (var arg in TemplateArguments)
|
||||
wrapper.TypeParameters.Add (arg);
|
||||
|
||||
if (Atoms.Count == 0) {
|
||||
wrapper.Comments.Add (new CodeCommentStatement ("FIXME: This type is a stub."));
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
var iface = CreateInterface (wrapper);
|
||||
wrapper.Members.Add (iface);
|
||||
|
||||
|
@ -88,17 +103,21 @@ namespace Mono.VisualC.Code.Atoms {
|
|||
native.TypeReference (),
|
||||
wrapper.TypeReference ()
|
||||
};
|
||||
var getClassMethod = new CodeMethodReferenceExpression (new CodeTypeReferenceExpression (StaticCppLibrary), "GetClass", types);
|
||||
var getClassMethod = new CodeMethodReferenceExpression (new CodeTypeReferenceExpression (new CodeTypeReference (StaticCppLibrary, CodeTypeReferenceOptions.GlobalReference)), "GetClass", types);
|
||||
implField.InitExpression = new CodeMethodInvokeExpression (getClassMethod, new CodePrimitiveExpression (Name));
|
||||
}
|
||||
wrapper.Members.Add (implField);
|
||||
|
||||
// always add native subclass ctor
|
||||
wrapper.Members.Add (CreateNativeSubclassConstructor (hasOverrides));
|
||||
|
||||
CodeMemberMethod dispose = null;
|
||||
foreach (var atom in Atoms) {
|
||||
Method method = atom as Method;
|
||||
if (method != null && method.IsDestructor)
|
||||
if (method != null && method.IsDestructor) {
|
||||
dispose = (CodeMemberMethod)method.InsideCodeTypeDeclaration (wrapper);
|
||||
else
|
||||
atom.Visit (dispose);
|
||||
} else
|
||||
atom.Visit (wrapper);
|
||||
}
|
||||
|
||||
|
@ -153,6 +172,26 @@ namespace Mono.VisualC.Code.Atoms {
|
|||
return native;
|
||||
}
|
||||
|
||||
private CodeConstructor CreateNativeSubclassConstructor (bool callBase)
|
||||
{
|
||||
var ctor = new CodeConstructor {
|
||||
Name = this.Name,
|
||||
Attributes = MemberAttributes.Assembly
|
||||
};
|
||||
ctor.Parameters.Add (new CodeParameterDeclarationExpression (typeof (CppTypeInfo).Name, "subClass"));
|
||||
|
||||
// FIXME: Again, will this always work?
|
||||
var implTypeInfo = new CodeFieldReferenceExpression (new CodeFieldReferenceExpression { FieldName = "impl" }, "TypeInfo");
|
||||
|
||||
if (callBase)
|
||||
ctor.BaseConstructorArgs.Add (implTypeInfo);
|
||||
|
||||
var addBase = new CodeMethodInvokeExpression (new CodeArgumentReferenceExpression ("subClass"), "AddBase", implTypeInfo);
|
||||
ctor.Statements.Add (addBase);
|
||||
|
||||
return ctor;
|
||||
}
|
||||
|
||||
private CodeMemberMethod CreateDestructorlessDispose ()
|
||||
{
|
||||
var dispose = new CodeMemberMethod {
|
||||
|
|
|
@ -24,8 +24,24 @@ namespace Mono.VisualC.Code.Atoms {
|
|||
}
|
||||
|
||||
internal protected override object InsideCodeNamespace (CodeNamespace ns)
|
||||
{
|
||||
ns.Types.Add (CreateEnumType ());
|
||||
return null;
|
||||
}
|
||||
|
||||
internal protected override object InsideCodeTypeDeclaration (CodeTypeDeclaration decl)
|
||||
{
|
||||
if (!decl.IsClass)
|
||||
return null;
|
||||
|
||||
decl.Members.Add (CreateEnumType ());
|
||||
return null;
|
||||
}
|
||||
|
||||
public CodeTypeDeclaration CreateEnumType ()
|
||||
{
|
||||
var type = new CodeTypeDeclaration (Name) {
|
||||
Attributes = MemberAttributes.Public,
|
||||
TypeAttributes = TypeAttributes.Public,
|
||||
IsEnum = true
|
||||
};
|
||||
|
@ -33,7 +49,6 @@ namespace Mono.VisualC.Code.Atoms {
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ namespace Mono.VisualC.Code.Atoms {
|
|||
}
|
||||
|
||||
if (Type.ElementType == CppTypes.Enum || Type.ElementType == CppTypes.Union)
|
||||
return new CodeTypeReference (Type.ElementTypeName);
|
||||
return Type.TypeReference ();
|
||||
|
||||
if (Type.ElementType == CppTypes.Typename)
|
||||
return new CodeTypeReference (Type.ElementTypeName, CodeTypeReferenceOptions.GenericTypeParameter);
|
||||
|
|
|
@ -7,12 +7,12 @@ using System.CodeDom;
|
|||
|
||||
using Mono.VisualC.Interop;
|
||||
using Mono.VisualC.Interop.ABI;
|
||||
using Mono.VisualC.Interop.Util;
|
||||
|
||||
namespace Mono.VisualC.Code.Atoms {
|
||||
|
||||
public class Method : CodeContainer {
|
||||
|
||||
public string Name { get; set; }
|
||||
public Access Access { get; set; }
|
||||
public bool IsVirtual { get; set; }
|
||||
public bool IsStatic { get; set; }
|
||||
|
@ -21,8 +21,11 @@ namespace Mono.VisualC.Code.Atoms {
|
|||
public bool IsDestructor { get; set; }
|
||||
|
||||
public CppType RetType { get; set; }
|
||||
|
||||
public IList<NameTypePair<CppType>> Parameters { get; set; }
|
||||
|
||||
private string formatted_name;
|
||||
|
||||
// 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 {
|
||||
|
@ -49,24 +52,30 @@ namespace Mono.VisualC.Code.Atoms {
|
|||
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)
|
||||
var method = CreateWrapperMethod (decl.BaseTypes [0].BaseType != typeof (ICppObject).Name);
|
||||
|
||||
if (method == null || CommentedOut)
|
||||
return null;
|
||||
|
||||
var method = CreateWrapperMethod ();
|
||||
if (Comment != null)
|
||||
method.Comments.Add (new CodeCommentStatement (Comment));
|
||||
|
||||
decl.Members.Add (method);
|
||||
return method;
|
||||
|
||||
} else if (decl.IsInterface) {
|
||||
CodeTypeMember method = CreateInterfaceMethod ();
|
||||
CodeTypeMember member;
|
||||
|
||||
if (CommentedOut) {
|
||||
member = new CodeSnippetTypeMember ();
|
||||
member.Comments.Add (new CodeCommentStatement (Comment));
|
||||
member.Comments.Add (new CodeCommentStatement (CreateInterfaceMethod ().CommentOut (current_code_provider)));
|
||||
member.Comments.Add (new CodeCommentStatement (method.CommentOut (current_code_provider)));
|
||||
|
||||
} else
|
||||
member = CreateInterfaceMethod ();
|
||||
member = method;
|
||||
|
||||
if (Comment != null)
|
||||
member.Comments.Insert (0, new CodeCommentStatement (Comment));
|
||||
|
||||
decl.Members.Add (member);
|
||||
}
|
||||
|
@ -77,8 +86,11 @@ namespace Mono.VisualC.Code.Atoms {
|
|||
internal protected override object InsideCodeStatementCollection (CodeStatementCollection stmts)
|
||||
{
|
||||
List<CodeExpression> arguments = new List<CodeExpression> ();
|
||||
var native = new CodeFieldReferenceExpression (new CodeThisReferenceExpression (), "Native");
|
||||
var native_ptr = new CodeFieldReferenceExpression (new CodeThisReferenceExpression (), "native_ptr");
|
||||
|
||||
if (!IsStatic)
|
||||
arguments.Add (new CodeFieldReferenceExpression (new CodeThisReferenceExpression (), "Native"));
|
||||
arguments.Add (native);
|
||||
|
||||
foreach (var param in Parameters) {
|
||||
// FIXME: handle typenames better
|
||||
|
@ -92,9 +104,15 @@ namespace Mono.VisualC.Code.Atoms {
|
|||
arguments.Add (new CodeArgumentReferenceExpression (param.Name));
|
||||
}
|
||||
|
||||
|
||||
// FIXME: Does just specifying the field name work for all code generators?
|
||||
var impl = new CodeFieldReferenceExpression { FieldName = "impl" };
|
||||
|
||||
|
||||
if (IsConstructor) {
|
||||
var alloc = new CodeMethodInvokeExpression (impl, "Alloc", new CodeThisReferenceExpression ());
|
||||
stmts.Add (new CodeAssignStatement (native_ptr, alloc));
|
||||
}
|
||||
|
||||
var invoke = new CodeMethodInvokeExpression (impl, Name, arguments.ToArray ());
|
||||
|
||||
if (RetType.Equals (CppTypes.Void))
|
||||
|
@ -102,16 +120,26 @@ namespace Mono.VisualC.Code.Atoms {
|
|||
else
|
||||
stmts.Add (new CodeMethodReturnStatement (invoke));
|
||||
|
||||
if (IsDestructor)
|
||||
stmts.Add (new CodeMethodInvokeExpression (native, "Dispose"));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private CodeMemberMethod CreateInterfaceMethod ()
|
||||
{
|
||||
var returnType = ReturnTypeReference;
|
||||
var method = new CodeMemberMethod {
|
||||
Name = this.Name,
|
||||
ReturnType = this.ReturnTypeReference
|
||||
ReturnType = returnType
|
||||
};
|
||||
|
||||
if (returnType == null) {
|
||||
Comment = "FIXME: Unknown return type \"" + RetType.ToString () + "\" for method \"" + Name + "\"";;
|
||||
CommentedOut = true;
|
||||
method.ReturnType = new CodeTypeReference (typeof (void));
|
||||
}
|
||||
|
||||
if (IsVirtual) method.CustomAttributes.Add (new CodeAttributeDeclaration ("Virtual"));
|
||||
if (IsConstructor) method.CustomAttributes.Add (new CodeAttributeDeclaration ("Constructor"));
|
||||
if (IsDestructor) method.CustomAttributes.Add (new CodeAttributeDeclaration ("Destructor"));
|
||||
|
@ -123,25 +151,44 @@ namespace Mono.VisualC.Code.Atoms {
|
|||
method.Parameters.Add (new CodeParameterDeclarationExpression (typeof (CppInstancePtr).Name, "this"));
|
||||
|
||||
if (hasMangledInfo)
|
||||
method.CustomAttributes.Add (new CodeAttributeDeclaration ("ValidateBindings",
|
||||
method.CustomAttributes.Add (new CodeAttributeDeclaration (typeof (AbiTestAttribute).Name,
|
||||
new CodeAttributeArgument (new CodePrimitiveExpression (Mangled.Name)),
|
||||
new CodeAttributeArgument ("Abi", new CodeTypeOfExpression (Mangled.Type))));
|
||||
foreach (var param in GetParameterDeclarations (true))
|
||||
for (int i = 0; i < Parameters.Count; i++) {
|
||||
var param = GenerateParameterDeclaration (Parameters [i]);
|
||||
string paramStr = Parameters [i].Type.ToString ();
|
||||
|
||||
if (param == null) {
|
||||
Comment = "FIXME: Unknown parameter type \"" + paramStr + "\" to method \"" + Name + "\"";
|
||||
CommentedOut = true;
|
||||
method.Parameters.Add (new CodeParameterDeclarationExpression (paramStr, Parameters [i].Name));
|
||||
continue;
|
||||
}
|
||||
|
||||
// FIXME: Only add MangleAs attribute if the managed type chosen would mangle differently by default
|
||||
if (!IsVirtual && !paramStr.Equals (string.Empty))
|
||||
param.CustomAttributes.Add (new CodeAttributeDeclaration ("MangleAs", new CodeAttributeArgument (new CodePrimitiveExpression (paramStr))));
|
||||
|
||||
method.Parameters.Add (param);
|
||||
}
|
||||
|
||||
return method;
|
||||
}
|
||||
|
||||
private CodeMemberMethod CreateWrapperMethod ()
|
||||
private CodeMemberMethod CreateWrapperMethod (bool hasBase)
|
||||
{
|
||||
CodeMemberMethod method;
|
||||
|
||||
if (IsConstructor)
|
||||
method = new CodeConstructor {
|
||||
if (IsConstructor) {
|
||||
var ctor = new CodeConstructor {
|
||||
Name = FormattedName,
|
||||
Attributes = MemberAttributes.Public
|
||||
};
|
||||
else if (IsDestructor)
|
||||
if (hasBase)
|
||||
ctor.BaseConstructorArgs.Add (new CodeFieldReferenceExpression (new CodeFieldReferenceExpression { FieldName = "impl" }, "TypeInfo"));
|
||||
|
||||
method = ctor;
|
||||
} else if (IsDestructor)
|
||||
method = new CodeMemberMethod {
|
||||
Name = "Dispose",
|
||||
Attributes = MemberAttributes.Public
|
||||
|
@ -163,8 +210,13 @@ namespace Mono.VisualC.Code.Atoms {
|
|||
else if (IsVirtual && !IsDestructor)
|
||||
method.CustomAttributes.Add (new CodeAttributeDeclaration ("OverrideNative"));
|
||||
|
||||
foreach (var param in GetParameterDeclarations (false))
|
||||
for (int i = 0; i < Parameters.Count; i++) {
|
||||
var param = GenerateParameterDeclaration (Parameters [i]);
|
||||
if (param == null)
|
||||
return null;
|
||||
|
||||
method.Parameters.Add (param);
|
||||
}
|
||||
|
||||
return method;
|
||||
}
|
||||
|
@ -189,51 +241,54 @@ namespace Mono.VisualC.Code.Atoms {
|
|||
}
|
||||
}
|
||||
|
||||
public IEnumerable<CodeParameterDeclarationExpression> GetParameterDeclarations ()
|
||||
private CodeParameterDeclarationExpression GenerateParameterDeclaration (NameTypePair<CppType> param)
|
||||
{
|
||||
return GetParameterDeclarations (false);
|
||||
}
|
||||
CodeParameterDeclarationExpression paramDecl;
|
||||
|
||||
private IEnumerable<CodeParameterDeclarationExpression> GetParameterDeclarations (bool includeMangleAttribute)
|
||||
{
|
||||
foreach (var param in Parameters) {
|
||||
CodeParameterDeclarationExpression paramDecl;
|
||||
if (param.Type.ElementType == CppTypes.Typename)
|
||||
paramDecl = new CodeParameterDeclarationExpression (param.Type.ElementTypeName, param.Name);
|
||||
|
||||
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)
|
||||
paramDecl = new CodeParameterDeclarationExpression (managedType.GetElementType (), param.Name) { Direction = FieldDirection.Ref };
|
||||
else if (managedType != null && managedType != typeof (ICppObject))
|
||||
paramDecl = new CodeParameterDeclarationExpression (managedType, param.Name);
|
||||
else
|
||||
paramDecl = new CodeParameterDeclarationExpression (param.Type.TypeReference (), param.Name);
|
||||
}
|
||||
else {
|
||||
Type managedType = param.Type.ToManagedType ();
|
||||
CodeTypeReference typeRef = param.Type.TypeReference ();
|
||||
|
||||
// FIXME: Only add MangleAs attribute if the managed type chosen would mangle differently by default
|
||||
string paramStr = param.Type.ToString ();
|
||||
if (includeMangleAttribute && !IsVirtual && !paramStr.Equals (string.Empty))
|
||||
paramDecl.CustomAttributes.Add (new CodeAttributeDeclaration ("MangleAs", new CodeAttributeArgument (new CodePrimitiveExpression (paramStr))));
|
||||
if (managedType != null && managedType.IsByRef)
|
||||
paramDecl = new CodeParameterDeclarationExpression (managedType.GetElementType (), param.Name) { Direction = FieldDirection.Ref };
|
||||
|
||||
else if (managedType != null && managedType != typeof (ICppObject))
|
||||
paramDecl = new CodeParameterDeclarationExpression (managedType, param.Name);
|
||||
|
||||
else if (typeRef != null)
|
||||
paramDecl = new CodeParameterDeclarationExpression (typeRef, param.Name);
|
||||
|
||||
else
|
||||
return null;
|
||||
|
||||
yield return paramDecl;
|
||||
}
|
||||
|
||||
return paramDecl;
|
||||
}
|
||||
|
||||
public string FormattedName {
|
||||
get {
|
||||
string upper = Name.ToUpper ();
|
||||
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]);
|
||||
if (formatted_name == null) {
|
||||
string upper = Name.ToUpper ();
|
||||
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]);
|
||||
}
|
||||
formatted_name = sb.ToString ();
|
||||
}
|
||||
return sb.ToString ();
|
||||
return formatted_name;
|
||||
}
|
||||
set {
|
||||
formatted_name = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.CodeDom;
|
||||
|
||||
namespace Mono.VisualC.Code.Atoms {
|
||||
public class Namespace : CodeContainer {
|
||||
|
||||
public Namespace (string name)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
|
||||
internal protected override object InsideCodeCompileUnit (CodeCompileUnit ccu)
|
||||
{
|
||||
CreateNamespace (ccu, Name);
|
||||
return null;
|
||||
}
|
||||
|
||||
internal protected override object InsideCodeNamespace (CodeNamespace ns)
|
||||
{
|
||||
CodeCompileUnit ccu = ns.UserData ["CodeCompileUnit"] as CodeCompileUnit;
|
||||
if (ccu == null)
|
||||
throw new NotSupportedException ("Invalid CodeNamespace");
|
||||
|
||||
CreateNamespace (ccu, ns.Name + "." + Name);
|
||||
return null;
|
||||
}
|
||||
|
||||
private void CreateNamespace (CodeCompileUnit ccu, string name)
|
||||
{
|
||||
CodeNamespace ns = new CodeNamespace (name);
|
||||
ns.Imports.Add (new CodeNamespaceImport ("Mono.VisualC.Interop"));
|
||||
|
||||
ns.UserData ["CodeCompileUnit"] = ccu;
|
||||
|
||||
foreach (var atom in Atoms)
|
||||
atom.Visit (ns);
|
||||
|
||||
ccu.Namespaces.Add (ns);
|
||||
}
|
||||
|
||||
public override void Write (TextWriter writer)
|
||||
{
|
||||
writer.WriteLine ("namespace {0} {{", Name);
|
||||
base.Write (writer);
|
||||
writer.WriteLine ("}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -66,7 +66,6 @@ namespace Mono.VisualC.Code.Atoms {
|
|||
NotDefined
|
||||
}
|
||||
public Condition IfCondition {get; set;}
|
||||
public string Name {get; set;}
|
||||
public PoundIfDef (Condition condition, string name) {
|
||||
IfCondition = condition;
|
||||
Name = name;
|
||||
|
|
|
@ -8,8 +8,6 @@ namespace Mono.VisualC.Code.Atoms {
|
|||
|
||||
public class Union : CodeContainer {
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public Union (string name)
|
||||
{
|
||||
Name = name;
|
||||
|
@ -19,9 +17,11 @@ namespace Mono.VisualC.Code.Atoms {
|
|||
{
|
||||
var union = new CodeTypeDeclaration (Name) {
|
||||
Attributes = MemberAttributes.Public,
|
||||
TypeAttributes = TypeAttributes.Public | TypeAttributes.ExplicitLayout,
|
||||
TypeAttributes = TypeAttributes.Public,
|
||||
IsStruct = true
|
||||
};
|
||||
var explicitLayout = new CodeAttributeArgument (new CodeFieldReferenceExpression (new CodeTypeReferenceExpression (typeof (LayoutKind)), "Explicit"));
|
||||
union.CustomAttributes.Add (new CodeAttributeDeclaration (new CodeTypeReference (typeof (StructLayoutAttribute)), explicitLayout));
|
||||
|
||||
foreach (var atom in Atoms) {
|
||||
Field field = atom as Field;
|
||||
|
@ -44,6 +44,9 @@ namespace Mono.VisualC.Code.Atoms {
|
|||
|
||||
internal protected override object InsideCodeTypeDeclaration (CodeTypeDeclaration decl)
|
||||
{
|
||||
if (!decl.IsClass)
|
||||
return null;
|
||||
|
||||
decl.Members.Add (CreateUnionType ());
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -13,16 +13,11 @@ namespace Mono.VisualC.Code {
|
|||
public string Comment { get; set; }
|
||||
public bool CommentedOut { get; set; }
|
||||
|
||||
protected CodeDomProvider current_code_provider;
|
||||
[ThreadStatic]
|
||||
protected static 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) {
|
||||
|
@ -33,8 +28,6 @@ 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)
|
||||
|
|
|
@ -1,16 +1,20 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using System.CodeDom;
|
||||
using System.CodeDom.Compiler;
|
||||
|
||||
using Mono.VisualC.Code.Atoms;
|
||||
|
||||
namespace Mono.VisualC.Code {
|
||||
|
||||
public abstract class CodeContainer : CodeAtom {
|
||||
|
||||
private LinkedList<CodeAtom> containedAtoms;
|
||||
public string IndentString {get; set;}
|
||||
public string Name { get; set; }
|
||||
|
||||
public CodeContainer (string indentString)
|
||||
{
|
||||
|
@ -26,6 +30,19 @@ namespace Mono.VisualC.Code {
|
|||
get { return containedAtoms; }
|
||||
}
|
||||
|
||||
|
||||
// Convenience method
|
||||
public virtual void AddToNamespace (string name, CodeAtom atom)
|
||||
{
|
||||
Namespace ns = Atoms.OfType<Namespace> ().Where (n => n.Name == name).SingleOrDefault ();
|
||||
if (ns == null) {
|
||||
ns = new Namespace (name);
|
||||
Atoms.AddLast (ns);
|
||||
}
|
||||
|
||||
ns.Atoms.AddLast (atom);
|
||||
}
|
||||
|
||||
public override void Write (TextWriter writer)
|
||||
{
|
||||
IndentedTextWriter itw = new IndentedTextWriter (writer, IndentString);
|
||||
|
|
|
@ -14,8 +14,11 @@ namespace Mono.VisualC.Code {
|
|||
|
||||
public static CodeComment CommentOut (this CodeTypeMember code, CodeDomProvider provider)
|
||||
{
|
||||
// FIXME: Not implemented ini mono
|
||||
//return CommentOut (provider.GenerateCodeFromMember, code);
|
||||
// FIXME: Not implemented in mono
|
||||
try {
|
||||
return CommentOut (provider.GenerateCodeFromMember, code);
|
||||
} catch (NotImplementedException) {}
|
||||
|
||||
return new CodeComment ();
|
||||
}
|
||||
public static CodeComment CommentOut (this CodeStatement code, CodeDomProvider provider)
|
||||
|
@ -53,11 +56,15 @@ namespace Mono.VisualC.Code {
|
|||
from p in m.Types
|
||||
select p.TypeReference (true);
|
||||
|
||||
Type managedType = useManagedType? t.ToManagedType () : null;
|
||||
if (managedType == typeof (ICppObject))
|
||||
managedType = null;
|
||||
Type managedType = useManagedType && (t.ElementType != CppTypes.Typename)? t.ToManagedType () : null;
|
||||
|
||||
return new CodeTypeReference (managedType != null ? managedType.FullName : t.ElementTypeName, tempParm.ToArray ());
|
||||
if ((managedType == null || managedType == typeof (ICppObject)) && t.ElementTypeName != null) {
|
||||
string qualifiedName = t.Namespaces != null? string.Join (".", t.Namespaces) + "." + t.ElementTypeName : t.ElementTypeName;
|
||||
return new CodeTypeReference (qualifiedName, tempParm.ToArray ());
|
||||
} else if (managedType != null)
|
||||
return new CodeTypeReference (managedType.FullName, tempParm.ToArray ());
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static CodeTypeReference [] TypeParameterReferences (this CodeTypeDeclaration ctd)
|
||||
|
|
|
@ -18,7 +18,11 @@ namespace Mono.VisualC.Code {
|
|||
public virtual CodeCompileUnit WrapperToCodeDom (CodeDomProvider provider)
|
||||
{
|
||||
CodeCompileUnit ccu = new CodeCompileUnit ();
|
||||
Visit (ccu, provider);
|
||||
ccu.UserData ["CodeAtom"] = this;
|
||||
|
||||
current_code_provider = provider;
|
||||
Visit (ccu);
|
||||
current_code_provider = null;
|
||||
|
||||
return ccu;
|
||||
}
|
||||
|
@ -27,8 +31,10 @@ namespace Mono.VisualC.Code {
|
|||
{
|
||||
CodeNamespace ns = new CodeNamespace (ManagedNamespace);
|
||||
ns.Imports.Add (new CodeNamespaceImport ("Mono.VisualC.Interop"));
|
||||
ccu.Namespaces.Add (ns);
|
||||
|
||||
ns.UserData ["CodeCompileUnit"] = ccu;
|
||||
|
||||
ccu.Namespaces.Add (ns);
|
||||
return ns;
|
||||
}
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
<Compile Include="Atoms\Field.cs" />
|
||||
<Compile Include="Atoms\Union.cs" />
|
||||
<Compile Include="NameTypePair.cs" />
|
||||
<Compile Include="Atoms\Namespace.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<ItemGroup>
|
||||
|
|
|
@ -57,8 +57,13 @@ namespace Mono.VisualC.Interop.ABI {
|
|||
|
||||
// The members below must be implemented for a given C++ ABI:
|
||||
|
||||
public abstract string GetMangledMethodName (MethodInfo methodInfo);
|
||||
public abstract CallingConvention? GetCallingConvention (MethodInfo methodInfo);
|
||||
protected abstract string GetMangledMethodName (MethodInfo methodInfo);
|
||||
public string GetMangledMethodName (string className, MethodInfo methodInfo)
|
||||
{
|
||||
class_name = className;
|
||||
return GetMangledMethodName (methodInfo);
|
||||
}
|
||||
|
||||
// The ImplementClass overrides are the main entry point to the Abi API:
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ namespace Mono.VisualC.Interop.ABI {
|
|||
return CallingConvention.Cdecl;
|
||||
}
|
||||
|
||||
public override string GetMangledMethodName (MethodInfo methodInfo)
|
||||
protected override string GetMangledMethodName (MethodInfo methodInfo)
|
||||
{
|
||||
string methodName = methodInfo.Name;
|
||||
MethodType methodType = GetMethodType (methodInfo);
|
||||
|
|
|
@ -40,7 +40,7 @@ namespace Mono.VisualC.Interop.ABI {
|
|||
return CallingConvention.ThisCall;
|
||||
}
|
||||
|
||||
public override string GetMangledMethodName (MethodInfo methodInfo)
|
||||
protected override string GetMangledMethodName (MethodInfo methodInfo)
|
||||
{
|
||||
string methodName = methodInfo.Name;
|
||||
MethodType methodType = GetMethodType (methodInfo);
|
||||
|
|
|
@ -30,7 +30,7 @@ namespace Mono.VisualC.Interop.ABI {
|
|||
return defaultType;
|
||||
}
|
||||
|
||||
public override string GetMangledMethodName (MethodInfo methodInfo)
|
||||
protected override string GetMangledMethodName (MethodInfo methodInfo)
|
||||
{
|
||||
throw new NotSupportedException ("Name mangling is not supported by this class. All C++ interface methods must be declared virtual.");
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Mono.VisualC.Interop {
|
||||
|
||||
|
@ -61,11 +60,11 @@ namespace Mono.VisualC.Interop {
|
|||
|
||||
// for testing:
|
||||
[AttributeUsage (AttributeTargets.Method)]
|
||||
public class ValidateBindingsAttribute : Attribute {
|
||||
public class AbiTestAttribute : Attribute {
|
||||
public string MangledName { get; set; }
|
||||
public Type Abi { get; set; }
|
||||
|
||||
public ValidateBindingsAttribute (string mangledName)
|
||||
public AbiTestAttribute (string mangledName)
|
||||
{
|
||||
MangledName = mangledName;
|
||||
}
|
||||
|
@ -115,7 +114,7 @@ using Mono.VisualC.Interop;
|
|||
// this means that either no MangleAsAttribute was defined, or
|
||||
// only CppModifiers were applied .. apply CppType from managed parameter type
|
||||
if (mangleType.ElementType == CppTypes.Unknown && mangleType.ElementTypeName == null)
|
||||
mangleType.ApplyTo (CppType.ForManagedType (managedType));
|
||||
mangleType.CopyTypeFrom (CppType.ForManagedType (managedType));
|
||||
else if (mangleType.ElementType == CppTypes.Unknown)
|
||||
// FIXME: otherwise, we just assume it's CppTypes.Class for now.
|
||||
mangleType.ElementType = CppTypes.Class;
|
||||
|
@ -123,11 +122,6 @@ using Mono.VisualC.Interop;
|
|||
return mangleType;
|
||||
}
|
||||
|
||||
[Conditional ("VALIDATE")]
|
||||
public virtual void ValidateBindings (MemberInfo member)
|
||||
{
|
||||
throw new NotImplementedException ();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -12,31 +12,56 @@ using System.Linq;
|
|||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
using Mono.VisualC.Interop.Util;
|
||||
|
||||
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 }
|
||||
// The list should be prioritized, in that the first items should be modifiers that can potentially contain other modifiers
|
||||
public static readonly Dictionary<string,Action<Match,List<CppModifiers>>> Tokenize = new Dictionary<string,Action<Match,List<CppModifiers>>> () {
|
||||
{ "\\<(.*)\\>", (m,l) => l.AddFirst (m.Groups [1].Success && m.Groups [1].Value.Trim () != ""? new TemplateModifier (m.Groups [1].Value) : CppModifiers.Template) },
|
||||
{ "\\[([^\\]]*)\\]", (m,l) => l.Add (m.Groups [1].Success && m.Groups [1].Value.Trim () != ""? new ArrayModifier (int.Parse (m.Groups [1].Value)) : CppModifiers.Array) },
|
||||
{ "\\bconst\\b", (m,l) => l.Add (CppModifiers.Const) },
|
||||
{ "\\*", (m,l) => l.Add (CppModifiers.Pointer) },
|
||||
{ "\\&", (m,l) => l.Add (CppModifiers.Reference) },
|
||||
{ "\\bvolatile\\b", (m,l) => l.Add (CppModifiers.Volatile) },
|
||||
{ "\\bunsigned\\b", (m,l) => l.Add (CppModifiers.Unsigned) },
|
||||
{ "\\bsigned\\b", (m,l) => l.Add (CppModifiers.Signed) },
|
||||
{ "\\bshort\\b", (m,l) => l.Add (CppModifiers.Short) },
|
||||
{ "\\blong\\b", (m,l) => l.Add (CppModifiers.Long) }
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
private struct Token {
|
||||
public Action<Match, List<CppModifiers>> action;
|
||||
public Match match;
|
||||
}
|
||||
private static IEnumerable<Token> Tokenizer (string input) {
|
||||
|
||||
foreach (var token in Tokenize) {
|
||||
Match match;
|
||||
|
||||
while ((match = Regex.Match (input, token.Key)) != null && match.Success) {
|
||||
yield return new Token { match = match, action = token.Value };
|
||||
input = input.Remove (match.Index, match.Length);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static List<CppModifiers> Parse (string input)
|
||||
{
|
||||
List<CppModifiers> cpm = new List<CppModifiers> ();
|
||||
var tokenizer = Tokenizer (input);
|
||||
|
||||
foreach (var token in tokenizer.OrderBy (t => t.match.Index))
|
||||
token.action (token.match, cpm);
|
||||
|
||||
return cpm;
|
||||
}
|
||||
|
||||
// removes any modifiers from the passed input
|
||||
public static string Remove (string input)
|
||||
{
|
||||
foreach (var token in Tokenize)
|
||||
|
@ -45,6 +70,23 @@ namespace Mono.VisualC.Interop {
|
|||
return input;
|
||||
}
|
||||
|
||||
// normalizes the order of order-agnostic modifiers
|
||||
public static IEnumerable<CppModifiers> NormalizeOrder (IEnumerable<CppModifiers> modifiers)
|
||||
{
|
||||
var parts = modifiers.Transform (
|
||||
For.AllInputsIn (CppModifiers.Unsigned, CppModifiers.Long).InAnyOrder ().Emit (new CppModifiers [] { CppModifiers.Unsigned, CppModifiers.Long }),
|
||||
For.AllInputsIn (CppModifiers.Signed, CppModifiers.Long).InAnyOrder ().Emit (new CppModifiers [] { CppModifiers.Signed, CppModifiers.Long }),
|
||||
For.AllInputsIn (CppModifiers.Unsigned, CppModifiers.Short).InAnyOrder ().Emit (new CppModifiers [] { CppModifiers.Unsigned, CppModifiers.Short }),
|
||||
For.AllInputsIn (CppModifiers.Signed, CppModifiers.Short).InAnyOrder ().Emit (new CppModifiers [] { CppModifiers.Signed, CppModifiers.Short }),
|
||||
|
||||
For.UnmatchedInput<CppModifiers> ().Emit (cppmod => new CppModifiers [] { cppmod })
|
||||
);
|
||||
|
||||
foreach (var array in parts)
|
||||
foreach (var item in array)
|
||||
yield return item;
|
||||
}
|
||||
|
||||
public override bool Equals (object obj)
|
||||
{
|
||||
return this == obj as CppModifiers;
|
||||
|
|
|
@ -58,14 +58,14 @@ namespace Mono.VisualC.Interop {
|
|||
(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,
|
||||
(t) => t.Modifiers.Contains (CppModifiers.Array) && (t.Subtract (CppModifiers.Array).ToManagedType () != null)? t.Subtract (CppModifiers.Array).ToManagedType ().MakeArrayType () : null,
|
||||
|
||||
// convert single pointers to primatives to managed byref
|
||||
(t) => t.Modifiers.Count (m => m == CppModifiers.Pointer) == 1? t.Subtract (CppModifiers.Pointer).ToManagedType ().MakeByRefType () : null,
|
||||
(t) => t.Modifiers.Count (m => m == CppModifiers.Pointer) == 1 && (t.Subtract (CppModifiers.Pointer).ToManagedType () != null)? t.Subtract (CppModifiers.Pointer).ToManagedType ().MakeByRefType () : null,
|
||||
// more than one level of indirection gets IntPtr type
|
||||
(t) => t.Modifiers.Contains (CppModifiers.Pointer)? typeof (IntPtr) : null,
|
||||
|
||||
(t) => t.Modifiers.Contains (CppModifiers.Reference)? t.Subtract (CppModifiers.Reference).ToManagedType ().MakeByRefType () : null,
|
||||
(t) => t.Modifiers.Contains (CppModifiers.Reference) && (t.Subtract (CppModifiers.Reference).ToManagedType () != null)? 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.Long) && t.Modifiers.Contains (CppModifiers.Unsigned)? typeof (ulong) : null,
|
||||
|
@ -127,6 +127,9 @@ namespace Mono.VisualC.Interop {
|
|||
// this will contain the name of said type
|
||||
public string ElementTypeName { get; set; }
|
||||
|
||||
// may be null, and will certainly be null if ElementTypeName is null
|
||||
public string [] Namespaces { get; set; }
|
||||
|
||||
// this is initialized lazily to avoid unnecessary heap
|
||||
// allocations if possible
|
||||
private List<CppModifiers> internalModifiers;
|
||||
|
@ -150,10 +153,13 @@ namespace Mono.VisualC.Interop {
|
|||
{
|
||||
ElementType = CppTypes.Unknown;
|
||||
ElementTypeName = null;
|
||||
Namespaces = null;
|
||||
internalModifiers = null;
|
||||
|
||||
Parse (cppTypeSpec);
|
||||
}
|
||||
|
||||
// FIXME: This makes no attempt to actually verify that the parts compose a valid C++ type.
|
||||
private void Parse (object [] parts)
|
||||
{
|
||||
foreach (object part in parts) {
|
||||
|
@ -176,15 +182,19 @@ namespace Mono.VisualC.Interop {
|
|||
Type managedType = part as Type;
|
||||
if (managedType != null) {
|
||||
CppType mapped = CppType.ForManagedType (managedType);
|
||||
ApplyTo (mapped);
|
||||
CopyTypeFrom (mapped);
|
||||
continue;
|
||||
}
|
||||
|
||||
string strPart = part as string;
|
||||
if (strPart != null) {
|
||||
var parsed = CppModifiers.Parse (strPart);
|
||||
if (parsed.Any ()) {
|
||||
Modifiers.AddRange (parsed);
|
||||
if (parsed.Count > 0) {
|
||||
if (internalModifiers == null)
|
||||
internalModifiers = parsed;
|
||||
else
|
||||
internalModifiers.AddRange (parsed);
|
||||
|
||||
strPart = CppModifiers.Remove (strPart);
|
||||
}
|
||||
|
||||
|
@ -192,6 +202,15 @@ namespace Mono.VisualC.Interop {
|
|||
strPart = strPart.Trim ();
|
||||
if (strPart != "") {
|
||||
|
||||
string [] qualifiedName = strPart.Split (new string [] { "::" }, StringSplitOptions.RemoveEmptyEntries);
|
||||
int numNamespaces = qualifiedName.Length - 1;
|
||||
if (numNamespaces > 0) {
|
||||
Namespaces = new string [numNamespaces];
|
||||
for (int i = 0; i < numNamespaces; i++)
|
||||
Namespaces [i] = qualifiedName [i];
|
||||
}
|
||||
strPart = qualifiedName [numNamespaces];
|
||||
|
||||
// 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);
|
||||
|
@ -210,10 +229,11 @@ namespace Mono.VisualC.Interop {
|
|||
// and combines its modifiers into this instance.
|
||||
// Use when THIS instance may have attributes you want,
|
||||
// but want the element type of the passed instance.
|
||||
public CppType ApplyTo (CppType type)
|
||||
public CppType CopyTypeFrom (CppType type)
|
||||
{
|
||||
ElementType = type.ElementType;
|
||||
ElementTypeName = type.ElementTypeName;
|
||||
Namespaces = type.Namespaces;
|
||||
|
||||
List<CppModifiers> oldModifiers = internalModifiers;
|
||||
internalModifiers = type.internalModifiers;
|
||||
|
@ -267,11 +287,16 @@ namespace Mono.VisualC.Interop {
|
|||
return false;
|
||||
CppType other = (CppType)obj;
|
||||
|
||||
// FIXME: the order of some modifiers is not significant
|
||||
return (((internalModifiers == null || !internalModifiers.Any ()) &&
|
||||
(other.internalModifiers == null || !other.internalModifiers.Any ())) ||
|
||||
(internalModifiers != null && other.internalModifiers != null &&
|
||||
internalModifiers.SequenceEqual (other.internalModifiers))) &&
|
||||
CppModifiers.NormalizeOrder (internalModifiers).SequenceEqual (CppModifiers.NormalizeOrder (other.internalModifiers)))) &&
|
||||
|
||||
(((Namespaces == null || !Namespaces.Any ()) &&
|
||||
(other.Namespaces == null || !other.Namespaces.Any ())) ||
|
||||
(Namespaces != null && other.Namespaces != null &&
|
||||
Namespaces.SequenceEqual (other.Namespaces))) &&
|
||||
|
||||
ElementType == other.ElementType &&
|
||||
ElementTypeName == other.ElementTypeName;
|
||||
}
|
||||
|
@ -282,6 +307,7 @@ namespace Mono.VisualC.Interop {
|
|||
unchecked {
|
||||
return (internalModifiers != null? internalModifiers.SequenceHashCode () : 0) ^
|
||||
ElementType.GetHashCode () ^
|
||||
(Namespaces != null? Namespaces.SequenceHashCode () : 0) ^
|
||||
(ElementTypeName != null? ElementTypeName.GetHashCode () : 0);
|
||||
}
|
||||
}
|
||||
|
@ -291,25 +317,22 @@ namespace Mono.VisualC.Interop {
|
|||
StringBuilder cppTypeString = new StringBuilder ();
|
||||
|
||||
if (ElementType != CppTypes.Unknown && ElementType != CppTypes.Typename)
|
||||
cppTypeString.Append (Enum.GetName (typeof (CppTypes), ElementType).ToLower ());
|
||||
cppTypeString.Append (Enum.GetName (typeof (CppTypes), ElementType).ToLower ()).Append (' ');
|
||||
|
||||
if (ElementTypeName != null && ElementType != CppTypes.Typename) {
|
||||
if (cppTypeString.Length > 0)
|
||||
cppTypeString.Append (' ');
|
||||
cppTypeString.Append (ElementTypeName);
|
||||
if (Namespaces != null) {
|
||||
foreach (var ns in Namespaces)
|
||||
cppTypeString.Append (ns).Append ("::");
|
||||
}
|
||||
|
||||
if (ElementTypeName != null && ElementType != CppTypes.Typename)
|
||||
cppTypeString.Append (ElementTypeName);
|
||||
|
||||
if (internalModifiers != null) {
|
||||
foreach (var modifier in internalModifiers) {
|
||||
string stringified = modifier.ToString ();
|
||||
|
||||
if (cppTypeString.Length > 0)
|
||||
cppTypeString.Append (' ');
|
||||
cppTypeString.Append (stringified);
|
||||
}
|
||||
foreach (var modifier in internalModifiers)
|
||||
cppTypeString.Append (' ').Append (modifier.ToString ());
|
||||
}
|
||||
|
||||
return cppTypeString.ToString ();
|
||||
return cppTypeString.ToString ().Trim ();
|
||||
}
|
||||
|
||||
public Type ToManagedType ()
|
||||
|
|
|
@ -155,6 +155,10 @@ namespace Mono.VisualC.Interop.Util {
|
|||
list.AddRange (items);
|
||||
list.AddRange (temp);
|
||||
}
|
||||
public static void AddFirst<T> (this List<T> list, T item)
|
||||
{
|
||||
list.Insert (0, item);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -21,13 +21,12 @@ using System.CodeDom.Compiler;
|
|||
using Microsoft.CSharp;
|
||||
|
||||
namespace CPPInterop {
|
||||
class Generator {
|
||||
public static readonly Regex TemplateRegEx = new Regex ("([^\\<]+)\\<(.+)\\>$");
|
||||
public class Generator {
|
||||
public static readonly string [] genericTypeArgs = new string [] { "T", "U", "V", "W", "X", "Y", "Z" };
|
||||
|
||||
public string Source { get; set; }
|
||||
public string Dir {get; set;}
|
||||
public bool ShouldValidate { get; set; }
|
||||
public bool AbiTest { get; set; }
|
||||
public string Library {get; set;}
|
||||
|
||||
private string nspace;
|
||||
|
@ -35,24 +34,27 @@ namespace CPPInterop {
|
|||
get { return nspace; }
|
||||
set {
|
||||
nspace = value;
|
||||
enumerations.ManagedNamespace = value;
|
||||
unions.ManagedNamespace = value;
|
||||
Tree.ManagedNamespace = value;
|
||||
//enumerations.ManagedNamespace = value;
|
||||
//unions.ManagedNamespace = value;
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<string, string> Classes;
|
||||
public HashSet<string> Enumerations;
|
||||
public HashSet<string> Unions;
|
||||
public Dictionary<string,CodeTypeDeclaration> UnknownTypes;
|
||||
public HashSet<string> UnknownTypes;
|
||||
|
||||
public CodeDomProvider Provider { get; set; }
|
||||
public CodeGeneratorOptions Options { get; set; }
|
||||
|
||||
private CodeUnit currentUnit;
|
||||
private CodeUnit enumerations;
|
||||
private CodeUnit unions;
|
||||
private CodeUnit Tree { get; set; }
|
||||
//private CodeUnit currentUnit;
|
||||
//private CodeUnit enumerations;
|
||||
//private CodeUnit unions;
|
||||
private Dictionary<string,Property> properties;
|
||||
|
||||
private int enumCount = 0;
|
||||
private int unionCount = 0;
|
||||
|
||||
private HashSet<string> fileList;
|
||||
|
||||
public static void Main (string[] args)
|
||||
|
@ -61,7 +63,7 @@ namespace CPPInterop {
|
|||
Generator gen = new Generator ();
|
||||
var p = new OptionSet () {
|
||||
{ "h|?|help", v => help = v != null },
|
||||
{ "validate", v => gen.ShouldValidate = v != null },
|
||||
{ "testabi", v => gen.AbiTest = v != null },
|
||||
{ "f=", v => gen.Source = v },
|
||||
{ "o=", v => gen.Dir = v },
|
||||
{ "ns=", v => gen.Namespace = v },
|
||||
|
@ -112,13 +114,11 @@ namespace CPPInterop {
|
|||
public Generator ()
|
||||
{
|
||||
Classes = new Dictionary<string, string>();
|
||||
UnknownTypes = new Dictionary<string,CodeTypeDeclaration> ();
|
||||
UnknownTypes = new HashSet<string> ();
|
||||
|
||||
Enumerations = new HashSet<string> ();
|
||||
Unions = new HashSet<string> ();
|
||||
|
||||
enumerations = new CodeUnit { ManagedNamespace = Namespace };
|
||||
unions = new CodeUnit { ManagedNamespace = Namespace };
|
||||
Tree = new CodeUnit { ManagedNamespace = Namespace };
|
||||
//enumerations = new CodeUnit { ManagedNamespace = Namespace };
|
||||
//unions = new CodeUnit { ManagedNamespace = Namespace };
|
||||
properties = new Dictionary<string, Property> ();
|
||||
|
||||
fileList = new HashSet<string> ();
|
||||
|
@ -127,77 +127,101 @@ namespace CPPInterop {
|
|||
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);
|
||||
|
||||
// save files
|
||||
Save ();
|
||||
GenerateStaticLibField ();
|
||||
|
||||
if (enumerations.Atoms.Any ())
|
||||
SaveFile (enumerations.WrapperToCodeDom (Provider), "Enums");
|
||||
if (unions.Atoms.Any ())
|
||||
SaveFile (unions.WrapperToCodeDom (Provider), "Unions");
|
||||
Console.WriteLine ("Validating bindings...");
|
||||
GenerateUnknownTypeStubs ();
|
||||
Assembly asm = Validate ();
|
||||
|
||||
if (ShouldValidate) {
|
||||
GenerateUnknownTypeStubs ();
|
||||
Validate ();
|
||||
//File.Delete (fileList.Where (f => f.StartsWith ("UnknownTypes")).Single ());
|
||||
if (asm != null && AbiTest) {
|
||||
Console.WriteLine ("Testing Itanium ABI name mangling against bindings...");
|
||||
TestAbi (asm);
|
||||
}
|
||||
//File.Delete (fileList.Where (f => f.StartsWith ("UnknownTypes")).Single ());
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void Save ()
|
||||
{
|
||||
//if (enumerations.Atoms.Any ())
|
||||
// SaveFile (enumerations.WrapperToCodeDom (Provider), "Enums");
|
||||
//if (unions.Atoms.Any ())
|
||||
// SaveFile (unions.WrapperToCodeDom (Provider), "Unions");
|
||||
|
||||
SaveFile (Tree.WrapperToCodeDom (Provider), "FlatFile");
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ProcessClasses (XmlDocument xmldoc)
|
||||
{
|
||||
XmlNodeList classes = xmldoc.SelectNodes ("/GCC_XML/Class[not(@incomplete)]");
|
||||
// FIXME: Figure out how to eliminate struct noise
|
||||
XmlNodeList classes = xmldoc.SelectNodes ("/GCC_XML/Class[not(@incomplete)]" /* |/GCC_XML/Struct[not(@incomplete)]" */);
|
||||
foreach (XmlNode clas in classes) {
|
||||
var f = xmldoc.SelectSingleNode ("/GCC_XML/File[@id='" + clas.Attributes["file"].Value + "']/@name");
|
||||
if (f != null && f.Value.StartsWith ("/"))
|
||||
continue;
|
||||
|
||||
string name = clas.Attributes["name"].Value;
|
||||
if (Classes.ContainsKey (name))
|
||||
if (clas.Attributes ["name"] == null || clas.Attributes ["name"].Value == "")
|
||||
continue;
|
||||
|
||||
// FIXME: better way to do this
|
||||
//currentUnit = new CodeUnit { ManagedNamespace = Namespace };
|
||||
|
||||
string name = clas.Attributes ["name"].Value;
|
||||
string ns = GetNamespace (xmldoc.DocumentElement, clas);
|
||||
CppType currentType = new CppType (clas.Name.ToLower (), ns != null? ns + "::" + name : name);
|
||||
IEnumerable<CodeAtom> nested = null;
|
||||
|
||||
// FIXME: better way to do this (GCC-XML output doesn't seem to leave much choice)
|
||||
CppType [] replaceArgs = null;
|
||||
Match m = TemplateRegEx.Match (name);
|
||||
if (m.Success) {
|
||||
string baseName = m.Groups [1].Value;
|
||||
if (Classes.ContainsKey (baseName))
|
||||
var templated = currentType.Modifiers.OfType<CppModifiers.TemplateModifier> ().SingleOrDefault ();
|
||||
if (templated != null) {
|
||||
string baseName = currentType.ElementTypeName;
|
||||
if (CheckType (currentType, true, out nested))
|
||||
continue;
|
||||
|
||||
replaceArgs = m.Groups [2].Value.Split (',').Select (s => new CppType (s)).ToArray ();
|
||||
replaceArgs = templated.Types;
|
||||
|
||||
string [] ras = new string [replaceArgs.Length];
|
||||
string [] letters = new string [replaceArgs.Length];
|
||||
for (int i = 0; i < replaceArgs.Length; i++) {
|
||||
letters [i] = genericTypeArgs [i];
|
||||
ras [i] = string.Format ("{0} with {1}", replaceArgs [i].ToString (), letters [i]);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
currentUnit = new CodeUnit { ManagedNamespace = Namespace };
|
||||
name = baseName;
|
||||
} else if (CheckType (currentType, true, out nested))
|
||||
continue;
|
||||
|
||||
|
||||
var classAtom = new Class (name) {
|
||||
StaticCppLibrary = string.Format ("{0}.Libs.{1}", Namespace, Library)
|
||||
};
|
||||
GetContainer (xmldoc.DocumentElement, clas, Tree).Atoms.AddLast (classAtom);
|
||||
//GetContainer (xmldoc.DocumentElement, clas, currentUnit).Atoms.AddLast (classAtom);
|
||||
|
||||
if (nested != null) {
|
||||
foreach (var orphan in nested)
|
||||
classAtom.Atoms.AddLast (orphan);
|
||||
}
|
||||
|
||||
// add tempate type args
|
||||
if (replaceArgs != null) {
|
||||
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);
|
||||
|
||||
// FIXME: Handle when base class name is fully qualified
|
||||
foreach (XmlNode baseNode in clas.SelectNodes ("Base")) {
|
||||
classAtom.Bases.Add (new Class.BaseClass {
|
||||
Name = find (xmldoc.DocumentElement, baseNode.Attributes ["type"]).Attributes ["name"].Value,
|
||||
|
@ -264,7 +288,7 @@ namespace CPPInterop {
|
|||
};
|
||||
|
||||
|
||||
if (ShouldValidate)
|
||||
if (AbiTest)
|
||||
methodAtom.Mangled = new NameTypePair<Type> { Name = n.Attributes ["mangled"].Value, Type = typeof (ItaniumAbi) };
|
||||
|
||||
XmlNodeList argNodes = n.SelectNodes ("Argument");
|
||||
|
@ -291,7 +315,7 @@ namespace CPPInterop {
|
|||
}
|
||||
|
||||
// Try to filter out duplicate methods
|
||||
MethodSignature sig = new MethodSignature { Name = methodAtom.FormattedName, Arguments = argTypes };
|
||||
MethodSignature sig = new MethodSignature (methodAtom.FormattedName, argTypes);
|
||||
string conflictingSig;
|
||||
if (methods.TryGetValue (sig, out conflictingSig)) {
|
||||
// FIXME: add comment to explain why it's commented out
|
||||
|
@ -337,9 +361,15 @@ namespace CPPInterop {
|
|||
string pname = methodAtom.FormattedName.Substring (3);
|
||||
Property propertyAtom = 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) {
|
||||
|
||||
// ...AND there is a corresponding getter method that returns the right type, then assume it's a property setter
|
||||
bool doIt = false;
|
||||
if (properties.TryGetValue (pname, out propertyAtom)) {
|
||||
doIt = propertyAtom.Getter.RetType.Equals (methodAtom.Parameters [0].Type);
|
||||
} else {
|
||||
XmlNode getter = findMethod (xmldoc.DocumentElement, members, getterName);
|
||||
doIt = (getter != null && findType (xmldoc.DocumentElement, getter.Attributes ["returns"]).Equals (methodAtom.Parameters [0].Type));
|
||||
}
|
||||
if (doIt) {
|
||||
if (propertyAtom != null) {
|
||||
propertyAtom.Setter = methodAtom;
|
||||
} else {
|
||||
|
@ -361,72 +391,205 @@ namespace CPPInterop {
|
|||
}
|
||||
|
||||
|
||||
SaveFile (currentUnit.WrapperToCodeDom (Provider), name);
|
||||
//SaveFile (currentUnit.WrapperToCodeDom (Provider), name);
|
||||
}
|
||||
}
|
||||
|
||||
void Validate ()
|
||||
Assembly Validate ()
|
||||
{
|
||||
Console.WriteLine ("Validating bindings...");
|
||||
|
||||
var compileParams = new CompilerParameters {
|
||||
GenerateInMemory = true,
|
||||
IncludeDebugInformation = true,
|
||||
WarningLevel = 0,
|
||||
TreatWarningsAsErrors = false
|
||||
};
|
||||
compileParams.ReferencedAssemblies.Add (typeof (CppLibrary).Assembly.CodeBase);
|
||||
|
||||
CompilerResults results = Provider.CompileAssemblyFromFile (compileParams, fileList.ToArray ());
|
||||
var errors = results.Errors.Cast<CompilerError> ().Where (e => !e.IsWarning);
|
||||
|
||||
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);
|
||||
int count = 0;
|
||||
foreach (var error in errors) {
|
||||
|
||||
Console.Error.WriteLine ("Validation failed with {0} compilation errors.", results.Errors.Count);
|
||||
if (count == 0) {
|
||||
foreach (var fix in Postfixes.List) {
|
||||
if (fix.TryFix (error.ErrorText, this))
|
||||
return Validate ();
|
||||
}
|
||||
}
|
||||
|
||||
Console.Error.WriteLine ("{0}({1},{2}): error {3}: {4}", error.FileName, error.Line, error.Column, error.ErrorNumber, error.ErrorText);
|
||||
count++;
|
||||
}
|
||||
if (count > 0)
|
||||
Console.Error.WriteLine ("Validation failed with {0} compilation errors.", count);
|
||||
else
|
||||
Console.WriteLine ("Bindings compiled successfully.");
|
||||
|
||||
//Type [] types = validationAssembly.GetExportedTypes ();
|
||||
// do stuff...
|
||||
|
||||
return results.CompiledAssembly;
|
||||
}
|
||||
|
||||
void TestAbi (Assembly assembly)
|
||||
{
|
||||
var classes = assembly.GetExportedTypes ().Select (t => new { Name = Regex.Replace (t.Name, "\\`.$", ""), Interface = t.GetNestedType ("I" + t.Name)})
|
||||
.Where (k => k.Interface != null);
|
||||
var abi = new ItaniumAbi ();
|
||||
|
||||
foreach (var klass in classes) {
|
||||
bool klassSuccess = true;
|
||||
|
||||
foreach (var method in klass.Interface.GetMethods ()) {
|
||||
|
||||
var testAttribute = (AbiTestAttribute)method.GetCustomAttributes (typeof (AbiTestAttribute), false).FirstOrDefault ();
|
||||
|
||||
string expected = testAttribute.MangledName;
|
||||
string actual = abi.GetMangledMethodName (klass.Name, method);
|
||||
|
||||
if (actual != expected) {
|
||||
Console.Error.WriteLine ("Error: Expected \"{0}\" but got \"{1}\" when mangling method \"{2}\" in class \"{3}\"", expected, actual, method.ToString (), klass.Name);
|
||||
klassSuccess = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (klassSuccess)
|
||||
Console.WriteLine ("Successfully mangled all method names in class \"" + klass.Name + "\"");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
CppType ProcessEnum (XmlNode enm)
|
||||
string GetNamespace (XmlNode root, XmlNode n)
|
||||
{
|
||||
XmlNode ns = find (root, n.Attributes ["context"]);
|
||||
if (ns == null)
|
||||
return null;
|
||||
|
||||
string nsname;
|
||||
if (ns.Name == "Namespace")
|
||||
nsname = ns.Attributes ["name"].Value;
|
||||
else if (ns.Name == "Class" || ns.Name == "Struct")
|
||||
nsname = new CppType (ns.Attributes ["name"].Value).ElementTypeName;
|
||||
else
|
||||
throw new NotSupportedException ("Unknown context: " + ns.Name);
|
||||
|
||||
if (nsname == "::")
|
||||
return null;
|
||||
|
||||
string parent = GetNamespace (root, ns);
|
||||
if (parent != null)
|
||||
return parent + "::" + nsname;
|
||||
|
||||
return nsname;
|
||||
}
|
||||
|
||||
CodeContainer GetContainer (XmlNode root, XmlNode n, CodeContainer def)
|
||||
{
|
||||
XmlNode ns = find (root, n.Attributes ["context"]);
|
||||
if (ns == null)
|
||||
return def;
|
||||
|
||||
string nsname;
|
||||
if (ns.Name == "Namespace")
|
||||
nsname = ns.Attributes ["name"].Value;
|
||||
else if (ns.Name == "Class" || ns.Name == "Struct")
|
||||
nsname = new CppType (ns.Attributes ["name"].Value).ElementTypeName;
|
||||
else
|
||||
throw new NotSupportedException ("Unknown context: " + ns.Name);
|
||||
|
||||
if (nsname == "::")
|
||||
return def;
|
||||
|
||||
CodeContainer parent = GetContainer (root, ns, def);
|
||||
CodeContainer container = parent.Atoms.OfType<CodeContainer> ().Where (a => a.Name == nsname).SingleOrDefault ();
|
||||
|
||||
if (container == null) {
|
||||
container = new Namespace (nsname);
|
||||
parent.Atoms.AddLast (container);
|
||||
}
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
public CodeContainer GetPath (string [] pathNames)
|
||||
{
|
||||
return GetPath (Tree, pathNames, false);
|
||||
}
|
||||
|
||||
static CodeContainer GetPath (CodeContainer root, string [] pathNames, bool create)
|
||||
{
|
||||
foreach (var item in pathNames) {
|
||||
CodeContainer prospect = root.Atoms.OfType<CodeContainer> ().Where (a => a.Name == item).SingleOrDefault ();
|
||||
if (prospect == null) {
|
||||
if (create) {
|
||||
prospect = new Namespace (item);
|
||||
root.Atoms.AddLast (prospect);
|
||||
} else
|
||||
return null;
|
||||
}
|
||||
|
||||
root = prospect;
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
CppType ProcessEnum (XmlNode root, XmlNode enm)
|
||||
{
|
||||
bool hasName = false;
|
||||
string ename = "Enum" + Enumerations.Count;
|
||||
string ename = "Enum" + enumCount++;
|
||||
|
||||
if (enm.Attributes ["name"] != null && enm.Attributes ["name"].Value != "") {
|
||||
hasName = true;
|
||||
ename = enm.Attributes ["name"].Value;
|
||||
}
|
||||
|
||||
if (!hasName || !Enumerations.Contains (ename)) {
|
||||
CppType enumType = new CppType (CppTypes.Enum, 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);
|
||||
if (hasName) {
|
||||
string ns = GetNamespace (root, enm);
|
||||
if (ns != null)
|
||||
enumType = new CppType (CppTypes.Enum, ns + "::" + ename);
|
||||
}
|
||||
|
||||
return new CppType (CppTypes.Enum, ename);
|
||||
IEnumerable<CodeAtom> dontCare;
|
||||
if (!hasName || !CheckType (enumType, true, out dontCare)) {
|
||||
|
||||
Enumeration enumAtom = new Enumeration (ename);
|
||||
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) });
|
||||
|
||||
//GetContainer (root, enm, flatUnit).Atoms.AddLast (enumAtom);
|
||||
|
||||
CodeContainer nested = GetContainer (root, enm, Tree);//GetContainer (root, enm, currentUnit);
|
||||
//if (hasName && !(nested is Class)) // assume it might be used by other classes
|
||||
// GetContainer (root, enm, enumerations).Atoms.AddLast (enumAtom);
|
||||
//else
|
||||
nested.Atoms.AddLast (enumAtom);
|
||||
}
|
||||
|
||||
return enumType;
|
||||
}
|
||||
|
||||
CppType ProcessUnion (XmlNode root, XmlNode union)
|
||||
{
|
||||
bool hasName = false;
|
||||
string uname = "Union" + Unions.Count;
|
||||
string uname = "Union" + unionCount++;
|
||||
|
||||
if (union.Attributes ["name"] != null && union.Attributes ["name"].Value != "") {
|
||||
hasName = true;
|
||||
uname = union.Attributes ["name"].Value;
|
||||
}
|
||||
|
||||
if (!hasName || !Unions.Contains (uname)) {
|
||||
CppType unionType = new CppType (CppTypes.Union, uname);
|
||||
|
||||
if (hasName) {
|
||||
string ns = GetNamespace (root, union);
|
||||
if (ns != null)
|
||||
unionType = new CppType (CppTypes.Union, ns + "::" + uname);
|
||||
}
|
||||
|
||||
IEnumerable<CodeAtom> orphans = null;
|
||||
if (!hasName || !CheckType (unionType, true, out orphans)) {
|
||||
|
||||
Union unionAtom = new Union (uname);
|
||||
foreach (string id in union.Attributes["members"].Value.Split (' ').Where (id => !id.Equals (string.Empty))) {
|
||||
|
@ -439,16 +602,22 @@ namespace CPPInterop {
|
|||
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);
|
||||
//GetContainer (root, union, flatUnit).Atoms.AddLast (unionAtom);
|
||||
|
||||
CodeContainer nested = GetContainer (root, union, Tree);//GetContainer (root, union, currentUnit);
|
||||
//if (hasName && !(nested is Class)) // assume it might be used by other classes
|
||||
// GetContainer (root, union, unions).Atoms.AddLast (unionAtom);
|
||||
//else
|
||||
nested.Atoms.AddLast (unionAtom);
|
||||
|
||||
if (orphans != null) {
|
||||
foreach (var orphan in orphans)
|
||||
unionAtom.Atoms.AddLast (orphan);
|
||||
}
|
||||
}
|
||||
|
||||
return new CppType (CppTypes.Union, uname);
|
||||
return unionType;
|
||||
}
|
||||
|
||||
void GenerateStaticLibField ()
|
||||
|
@ -476,22 +645,61 @@ namespace CPPInterop {
|
|||
}
|
||||
|
||||
void GenerateUnknownTypeStubs ()
|
||||
{
|
||||
{/*
|
||||
var ccu = new CodeCompileUnit ();
|
||||
var ns = new CodeNamespace (Namespace);
|
||||
|
||||
foreach (var type in UnknownTypes)
|
||||
ns.Types.Add (type.Value);
|
||||
foreach (var type in UnknownTypes) {
|
||||
var ctd = type.Value as CodeTypeDeclaration;
|
||||
var newNS = type.Value as CodeNamespace;
|
||||
|
||||
if (ctd != null)
|
||||
ns.Types.Add (ctd);
|
||||
else
|
||||
ccu.Namespaces.Add (newNS);
|
||||
}
|
||||
|
||||
ccu.Namespaces.Add (ns);
|
||||
SaveFile (ccu, "UnknownTypes");
|
||||
*/
|
||||
|
||||
var ukt = UnknownTypes.ToArray ();
|
||||
foreach (var unknownType in ukt) {
|
||||
CodeContainer container = Tree;
|
||||
CppType type = new CppType (unknownType);
|
||||
IEnumerable<CodeAtom> orphans;
|
||||
|
||||
if (CheckType (type, true, out orphans))
|
||||
continue;
|
||||
|
||||
if (type.Namespaces != null)
|
||||
container = GetPath (Tree, type.Namespaces, true);
|
||||
|
||||
var atom = new Class (type.ElementTypeName);
|
||||
|
||||
int i = 0;
|
||||
foreach (var param in type.Modifiers.OfType<CppModifiers.TemplateModifier> ()) {
|
||||
if (param.Types != null) {
|
||||
foreach (var t in param.Types)
|
||||
atom.TemplateArguments.Add (genericTypeArgs [i++]);
|
||||
} else
|
||||
atom.TemplateArguments.Add (genericTypeArgs [i++]);
|
||||
}
|
||||
|
||||
if (orphans != null) {
|
||||
foreach (var orphan in orphans)
|
||||
atom.Atoms.AddLast (orphan);
|
||||
}
|
||||
|
||||
container.Atoms.AddLast (atom);
|
||||
}
|
||||
}
|
||||
|
||||
void SaveFile (CodeCompileUnit ccu, string baseName)
|
||||
{
|
||||
string name = Path.Combine (Dir, fname (baseName));
|
||||
if (File.Exists (name) && fileList.Contains (name))
|
||||
return;
|
||||
File.Delete (name);
|
||||
if (File.Exists (name) && !fileList.Contains (name)) {
|
||||
int i = 1;
|
||||
while (File.Exists (Path.Combine (Dir, fname (baseName + i))))
|
||||
|
@ -513,6 +721,8 @@ namespace CPPInterop {
|
|||
{
|
||||
// FIXME: The order of some modifiers is not significant.. is this a problem?
|
||||
if (/* inType.ElementType == toReplace.ElementType && */
|
||||
((inType.Namespaces != null && toReplace.Namespaces != null && inType.Namespaces.SequenceEqual (toReplace.Namespaces)) ||
|
||||
inType.Namespaces == null && toReplace.Namespaces == null) &&
|
||||
inType.ElementTypeName == toReplace.ElementTypeName &&
|
||||
inType.Modifiers.StartsWith (toReplace.Modifiers))
|
||||
return new CppType (CppTypes.Typename, tn, inType.Modifiers.Skip (toReplace.Modifiers.Count).ToArray ());
|
||||
|
@ -524,31 +734,80 @@ namespace CPPInterop {
|
|||
return inType;
|
||||
}
|
||||
|
||||
// FIXME: Do something trickier than just throw ElementTypeName in here?
|
||||
void CheckType (CppType cpptype)
|
||||
// returns true if the type was already created
|
||||
bool CheckType (CppType type)
|
||||
{
|
||||
string type = cpptype.ElementTypeName;
|
||||
if (type == null) return;
|
||||
IEnumerable<CodeAtom> dontCare;
|
||||
return CheckType (type, false, out dontCare);
|
||||
}
|
||||
bool CheckType (CppType type, bool toBeCreated, out IEnumerable<CodeAtom> orphanedAtoms)
|
||||
{
|
||||
orphanedAtoms = null;
|
||||
if (type.ElementTypeName == null || type.ElementTypeName == "" || type.ElementType == CppTypes.Typename)
|
||||
return true;
|
||||
|
||||
bool typeFound = Classes.ContainsKey (type) || Enumerations.Contains (type) || Unions.Contains (type);
|
||||
bool alreadyUnknown = UnknownTypes.ContainsKey (type);
|
||||
// check template parameters recursively
|
||||
foreach (var paramType in type.Modifiers.OfType<CppModifiers.TemplateModifier> ().Where (t => t.Types != null).SelectMany (t => t.Types))
|
||||
CheckType (paramType);
|
||||
|
||||
if (!typeFound && !alreadyUnknown) {
|
||||
var ctd = new CodeTypeDeclaration (type) {
|
||||
bool typeFound = false;
|
||||
type.ElementType = CppTypes.Unknown;
|
||||
for (int i = 0; i < type.Modifiers.Count; i++) {
|
||||
if (type.Modifiers [i] != CppModifiers.Template)
|
||||
type.Modifiers.RemoveAt (i);
|
||||
}
|
||||
|
||||
string qualifiedName = type.ToString ();
|
||||
bool alreadyUnknown = UnknownTypes.Contains (qualifiedName);
|
||||
|
||||
CodeContainer place = Tree;
|
||||
if (type.Namespaces != null)
|
||||
place = GetPath (type.Namespaces);
|
||||
|
||||
if (place != null) {
|
||||
typeFound = place.Atoms.OfType<Class> ().Where (c => c.Name == type.ElementTypeName).Any () ||
|
||||
place.Atoms.OfType<Enumeration> ().Where (e => e.Name == type.ElementTypeName).Any () ||
|
||||
place.Atoms.OfType<Union> ().Where (u => u.Name == type.ElementTypeName).Any ();
|
||||
|
||||
var sameNamedNamespace = place.Atoms.OfType<Namespace> ().Where (ns => ns.Name == type.ElementTypeName).SingleOrDefault ();
|
||||
if (sameNamedNamespace != null) {
|
||||
orphanedAtoms = sameNamedNamespace.Atoms;
|
||||
|
||||
// FIXME: This could potentially be very slow
|
||||
Tree.Atoms.Remove (sameNamedNamespace);
|
||||
//currentUnit.Atoms.Remove (sameNamedNamespace);
|
||||
//enumerations.Atoms.Remove (sameNamedNamespace);
|
||||
//unions.Atoms.Remove (sameNamedNamespace);
|
||||
}
|
||||
}
|
||||
|
||||
if (!typeFound && !toBeCreated && !alreadyUnknown) {
|
||||
/*CodeObject codeObject;
|
||||
|
||||
var ctd = new CodeTypeDeclaration (type.ElementTypeName) {
|
||||
TypeAttributes = TypeAttributes.Public,
|
||||
IsClass = true,
|
||||
IsPartial = true
|
||||
IsClass = true
|
||||
};
|
||||
|
||||
if (cpptype.Modifiers.Contains (CppModifiers.Template)) {
|
||||
var template = cpptype.Modifiers.OfType<CppModifiers.TemplateModifier> ().Single ();
|
||||
codeObject = ctd;
|
||||
|
||||
if (type.Namespaces != null) {
|
||||
var ns = new CodeNamespace (Namespace + "." + string.Join (".", type.Namespaces));
|
||||
ns.Types.Add (ctd);
|
||||
codeObject = ns;
|
||||
}
|
||||
|
||||
var template = type.Modifiers.OfType<CppModifiers.TemplateModifier> ().SingleOrDefault ();
|
||||
if (template != null) {
|
||||
for (int i = 0; i < template.Types.Length; i++)
|
||||
ctd.TypeParameters.Add (genericTypeArgs [i]);
|
||||
}
|
||||
*/
|
||||
UnknownTypes.Add (qualifiedName);
|
||||
} else if ((typeFound || toBeCreated) && alreadyUnknown)
|
||||
UnknownTypes.Remove (qualifiedName);
|
||||
|
||||
UnknownTypes.Add (type, ctd);
|
||||
} else if (typeFound && alreadyUnknown)
|
||||
UnknownTypes.Remove (type);
|
||||
return typeFound;
|
||||
}
|
||||
|
||||
static XmlNode find (XmlNode root, XmlAttribute att)
|
||||
|
@ -602,14 +861,14 @@ namespace CPPInterop {
|
|||
|
||||
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));
|
||||
case "FundamentalType": return modifiers.CopyTypeFrom (new CppType (name));
|
||||
case "Class": return modifiers.CopyTypeFrom (new CppType (CppTypes.Class, name));
|
||||
case "Struct": return modifiers.CopyTypeFrom (new CppType (CppTypes.Struct, name));
|
||||
case "Union": return modifiers.CopyTypeFrom (ProcessUnion (root, n));
|
||||
case "Enumeration": return modifiers.CopyTypeFrom (ProcessEnum (root, n));
|
||||
|
||||
// FIXME: support function pointers betters
|
||||
case "FunctionType": return modifiers.ApplyTo (CppTypes.Void);
|
||||
case "FunctionType": return modifiers.CopyTypeFrom (CppTypes.Void);
|
||||
}
|
||||
|
||||
throw new NotImplementedException ("Unknown type node: " + n.Name);
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Mono.VisualC.Interop;
|
||||
using Mono.VisualC.Interop.Util;
|
||||
|
||||
|
@ -9,7 +11,20 @@ namespace CPPInterop {
|
|||
// signatures. The problem is, most of the types don't exist yet.
|
||||
public struct MethodSignature {
|
||||
public string Name;
|
||||
public CppType [] Arguments;
|
||||
public IEnumerable<CppType> Arguments;
|
||||
|
||||
public MethodSignature (string name, IEnumerable<CppType> args)
|
||||
{
|
||||
Name = name;
|
||||
|
||||
// This is kinda hacky, but it was the best I could come up with at the time.
|
||||
// Remove any modifiers that will affect the managed type signature.
|
||||
// FIXME: Subtract more?
|
||||
Arguments = args.Select (a => a.Subtract (CppModifiers.Const))
|
||||
.Select (a => a.Subtract (CppModifiers.Volatile))
|
||||
.Select (a => a.Modifiers.Count (m => m == CppModifiers.Long) > 1? a.Subtract (CppModifiers.Long) : a)
|
||||
.Select (a => a.ElementType == CppTypes.Char? a.Subtract (CppModifiers.Unsigned).Subtract (CppModifiers.Signed) : a);
|
||||
}
|
||||
|
||||
public override bool Equals (object obj)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Mono.VisualC.Code;
|
||||
using Mono.VisualC.Code.Atoms;
|
||||
|
||||
namespace CPPInterop {
|
||||
|
||||
public static class Postfixes {
|
||||
public static readonly List<IPostfix> List = new List<IPostfix> () {
|
||||
new DuplicateMemberFix ()
|
||||
};
|
||||
}
|
||||
|
||||
public interface IPostfix {
|
||||
bool TryFix (string errorMessage, Generator gen);
|
||||
|
||||
}
|
||||
|
||||
public class DuplicateMemberFix : IPostfix {
|
||||
private static readonly Regex ID = new Regex("The type `(.+)' already contains a definition for `(.+)'");
|
||||
|
||||
public DuplicateMemberFix ()
|
||||
{
|
||||
}
|
||||
|
||||
public bool TryFix (string errorMessage, Generator gen)
|
||||
{
|
||||
Match m = ID.Match (errorMessage);
|
||||
if (!m.Success)
|
||||
return false;
|
||||
|
||||
string typeName = m.Groups [1].Value;
|
||||
string oldMember = m.Groups [2].Value;
|
||||
string newMember = oldMember + "2";
|
||||
bool memberFound = false;
|
||||
|
||||
CodeContainer type = gen.GetPath (typeName.Split ('.').Skip (1).ToArray ());
|
||||
|
||||
foreach (var method in type.Atoms.OfType<Method> ()) {
|
||||
if (method.FormattedName == oldMember) {
|
||||
method.FormattedName = newMember;
|
||||
memberFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!memberFound) {
|
||||
foreach (var prop in type.Atoms.OfType<Property> ()) {
|
||||
if (prop.Name == oldMember) {
|
||||
prop.Name = newMember;
|
||||
memberFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (memberFound) {
|
||||
//Console.WriteLine ("Renaming \"{0}\" to \"{1}\" to prevent name collision in class \"{2}\" ...", oldMember, newMember, typeName);
|
||||
gen.Save ();
|
||||
}
|
||||
|
||||
return memberFound;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -18,7 +18,7 @@
|
|||
<DefineConstants>DEBUG</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Commandlineparameters>-f=/Users/Alex/OpenSource/gccxml/gccxml-build/bin/qapplication.xml -o=.</Commandlineparameters>
|
||||
<Commandlineparameters>--testabi -f=/Users/Alex/OpenSource/gccxml/gccxml-build/bin/qapplication.xml -o=. --ns=Foo --lib=LibFoo</Commandlineparameters>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>none</DebugType>
|
||||
|
@ -31,6 +31,7 @@
|
|||
<Compile Include="Main.cs" />
|
||||
<Compile Include="Options.cs" />
|
||||
<Compile Include="MethodSignature.cs" />
|
||||
<Compile Include="Postfixes.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System">
|
||||
|
|
Загрузка…
Ссылка в новой задаче