Browse Source

Based on Abhinav Tripathi's work: extracted delegates in order to reuse them.

Signed-off-by: Dimitar Dobrev <dpldobrev@yahoo.com>
pull/256/merge
Dimitar Dobrev 10 years ago
parent
commit
fbb2f941c4
  1. 76
      src/AST/FunctionExtensions.cs
  2. 3
      src/Generator/Driver.cs
  3. 35
      src/Generator/Generators/CSharp/CSharpMarshal.cs
  4. 133
      src/Generator/Generators/CSharp/CSharpTextTemplate.cs
  5. 4
      src/Generator/Generators/CSharp/CSharpTypePrinter.cs
  6. 131
      src/Generator/Passes/DelegatesPass.cs
  7. 2
      src/Generator/Passes/RenameRootNamespaces.cs

76
src/AST/FunctionExtensions.cs

@ -0,0 +1,76 @@ @@ -0,0 +1,76 @@
using System.Collections.Generic;
using System.Linq;
namespace CppSharp.AST
{
public static class FunctionExtensions
{
public static IEnumerable<Parameter> GatherInternalParams(this Function function,
bool isItaniumLikeAbi, bool universalDelegate = false)
{
var @params = new List<Parameter>();
var method = function as Method;
var isInstanceMethod = method != null && !method.IsStatic;
var pointer = new QualifiedType(new PointerType(new QualifiedType(new BuiltinType(PrimitiveType.Void))));
if (isInstanceMethod && !isItaniumLikeAbi)
{
@params.Add(new Parameter
{
QualifiedType = pointer,
Name = "instance"
});
}
if (!function.HasIndirectReturnTypeParameter &&
isInstanceMethod && isItaniumLikeAbi)
{
@params.Add(new Parameter
{
QualifiedType = pointer,
Name = "instance"
});
}
var i = 0;
foreach (var param in function.Parameters.Where(p => p.Kind != ParameterKind.OperatorParameter))
{
@params.Add(new Parameter
{
QualifiedType = universalDelegate && param.Kind == ParameterKind.IndirectReturnType ?
pointer : param.QualifiedType,
Kind = param.Kind,
Usage = param.Usage,
Name = universalDelegate ? "arg" + ++i : param.Name
});
if (param.Kind == ParameterKind.IndirectReturnType &&
isInstanceMethod && isItaniumLikeAbi)
{
@params.Add(new Parameter
{
QualifiedType = pointer,
Name = "instance"
});
}
}
if (method != null && method.IsConstructor)
{
var @class = (Class) method.Namespace;
if (!isItaniumLikeAbi && @class.Layout.HasVirtualBases)
{
@params.Add(new Parameter
{
QualifiedType = new QualifiedType(new BuiltinType(PrimitiveType.Int)),
Name = "__forBases"
});
}
}
return @params;
}
}
}

3
src/Generator/Driver.cs

@ -288,6 +288,9 @@ namespace CppSharp @@ -288,6 +288,9 @@ namespace CppSharp
TranslationUnitPasses.AddPass(new CheckVTableComponentsPass());
if (Options.IsCSharpGenerator)
TranslationUnitPasses.AddPass(new DelegatesPass());
if (Options.GenerateProperties)
TranslationUnitPasses.AddPass(new GetterSetterToPropertyPass());

35
src/Generator/Generators/CSharp/CSharpMarshal.cs

@ -1,5 +1,4 @@ @@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CppSharp.AST;
@ -56,29 +55,11 @@ namespace CppSharp.Generators.CSharp @@ -56,29 +55,11 @@ namespace CppSharp.Generators.CSharp
public CSharpMarshalNativeToManagedPrinter(CSharpMarshalContext context)
: base(context)
{
typePrinter = new CSharpTypePrinter(context.Driver);
}
public bool MarshalsParameter { get; set; }
public static string QualifiedIdentifier(Declaration decl)
{
var names = new List<string> { decl.Name };
var ctx = decl.Namespace;
while (ctx != null)
{
if (!string.IsNullOrWhiteSpace(ctx.Name))
names.Add(ctx.Name);
ctx = ctx.Namespace;
}
//if (Options.GenerateLibraryNamespace)
// names.Add(Options.OutputNamespace);
names.Reverse();
return string.Join(".", names);
}
public override bool VisitType(Type type, TypeQualifiers quals)
{
TypeMap typeMap;
@ -269,10 +250,10 @@ namespace CppSharp.Generators.CSharp @@ -269,10 +250,10 @@ namespace CppSharp.Generators.CSharp
Type returnType = Context.ReturnType.Type.Desugar();
// if the class is an abstract impl, use the original for the object map
var qualifiedClass = QualifiedIdentifier(originalClass);
var qualifiedClass = originalClass.Visit(typePrinter);
if (returnType.IsAddress())
Context.Return.Write(HandleReturnedPointer(@class, qualifiedClass));
Context.Return.Write(HandleReturnedPointer(@class, qualifiedClass.Type));
else
Context.Return.Write("{0}.{1}({2})", qualifiedClass, Helpers.CreateInstanceIdentifier, Context.ReturnVarName);
@ -318,7 +299,7 @@ namespace CppSharp.Generators.CSharp @@ -318,7 +299,7 @@ namespace CppSharp.Generators.CSharp
{
var originalClass = @class.OriginalClass ?? @class;
var ret = Generator.GeneratedIdentifier("result") + Context.ParameterIndex;
var qualifiedIdentifier = QualifiedIdentifier(@class);
var qualifiedIdentifier = @class.Visit(typePrinter);
Context.SupportBefore.WriteLine("{0} {1};", qualifiedIdentifier, ret);
Context.SupportBefore.WriteLine("if ({0} == IntPtr.Zero) {1} = {2};", Context.ReturnVarName, ret,
originalClass.IsRefType ? "null" : string.Format("new {0}()", qualifiedClass));
@ -351,6 +332,8 @@ namespace CppSharp.Generators.CSharp @@ -351,6 +332,8 @@ namespace CppSharp.Generators.CSharp
}
return ret;
}
private readonly CSharpTypePrinter typePrinter;
}
public class CSharpMarshalManagedToNativePrinter : CSharpMarshalPrinter
@ -358,6 +341,7 @@ namespace CppSharp.Generators.CSharp @@ -358,6 +341,7 @@ namespace CppSharp.Generators.CSharp
public CSharpMarshalManagedToNativePrinter(CSharpMarshalContext context)
: base(context)
{
typePrinter = new CSharpTypePrinter(context.Driver);
}
public override bool VisitType(Type type, TypeQualifiers quals)
@ -666,8 +650,7 @@ namespace CppSharp.Generators.CSharp @@ -666,8 +650,7 @@ namespace CppSharp.Generators.CSharp
return;
}
var qualifiedIdentifier = CSharpMarshalNativeToManagedPrinter.QualifiedIdentifier(
@class.OriginalClass ?? @class);
var qualifiedIdentifier = (@class.OriginalClass ?? @class).Visit(typePrinter);
Context.Return.Write(
"ReferenceEquals({0}, null) ? new {1}.Internal() : *({1}.Internal*) ({0}.{2})", param,
qualifiedIdentifier, Helpers.InstanceIdentifier);
@ -721,6 +704,8 @@ namespace CppSharp.Generators.CSharp @@ -721,6 +704,8 @@ namespace CppSharp.Generators.CSharp
{
return template.TemplatedFunction.Visit(this);
}
private readonly CSharpTypePrinter typePrinter;
}
public static class CSharpMarshalExtensions

133
src/Generator/Generators/CSharp/CSharpTextTemplate.cs

@ -8,6 +8,7 @@ using System.Text.RegularExpressions; @@ -8,6 +8,7 @@ using System.Text.RegularExpressions;
using System.Web.Util;
using CppSharp.AST;
using CppSharp.AST.Extensions;
using CppSharp.Passes;
using CppSharp.Types;
using CppSharp.Utils;
using Attribute = CppSharp.AST.Attribute;
@ -111,42 +112,6 @@ namespace CppSharp.Generators.CSharp @@ -111,42 +112,6 @@ namespace CppSharp.Generators.CSharp
#region Identifiers
// Takes a declaration (type, class etc.) that is referenced from a context, and the context.
// If the referenced name needs a qualification in the context, add it. Otherwise, return just the name.
private static string QualifiedIdentifierIfNeeded(Declaration reference)
{
var refNames = new Stack<string>();
var refCtx = reference;
while (refCtx != null)
{
if (!string.IsNullOrWhiteSpace(refCtx.Name))
refNames.Push(refCtx.Name);
refCtx = refCtx.Namespace;
}
return string.Join(".", refNames);
}
public string QualifiedIdentifier(Declaration decl)
{
var names = new List<string> { decl.Name };
var ctx = decl.Namespace;
while (ctx != null)
{
if (!string.IsNullOrWhiteSpace(ctx.Name))
names.Add(ctx.Name);
ctx = ctx.Namespace;
}
if (decl.GenerationKind == GenerationKind.Generate && Options.GenerateLibraryNamespace)
names.Add(Options.OutputNamespace);
names.Reverse();
return string.Join(".", names);
}
public static string GeneratedIdentifier(string id)
{
return Generator.GeneratedIdentifier(id);
@ -597,72 +562,6 @@ namespace CppSharp.Generators.CSharp @@ -597,72 +562,6 @@ namespace CppSharp.Generators.CSharp
return functions;
}
private IEnumerable<Parameter> GatherInternalParams(Function function, bool useOriginalParamNames = true)
{
var @params = new List<Parameter>();
var method = function as Method;
var isInstanceMethod = method != null && !method.IsStatic;
var pointer = new QualifiedType(new PointerType(new QualifiedType(new BuiltinType(PrimitiveType.Void))));
if (isInstanceMethod && Options.IsMicrosoftAbi)
{
@params.Add(new Parameter
{
QualifiedType = pointer,
Name = "instance"
});
}
if (!function.HasIndirectReturnTypeParameter &&
isInstanceMethod && Options.IsItaniumLikeAbi)
{
@params.Add(new Parameter
{
QualifiedType = pointer,
Name = "instance"
});
}
var i = 0;
foreach (var param in function.Parameters.Where(p => p.Kind != ParameterKind.OperatorParameter))
{
@params.Add(new Parameter
{
QualifiedType = param.QualifiedType,
Kind = param.Kind,
Usage = param.Usage,
Name = useOriginalParamNames ? param.Name : "arg" + ++i
});
if (param.Kind == ParameterKind.IndirectReturnType &&
isInstanceMethod && Options.IsItaniumLikeAbi)
{
@params.Add(new Parameter
{
QualifiedType = pointer,
Name = "instance"
});
}
}
if (method != null && method.IsConstructor)
{
var @class = (Class) method.Namespace;
if (Options.IsMicrosoftAbi && @class.Layout.HasVirtualBases)
{
@params.Add(new Parameter
{
QualifiedType = new QualifiedType(new BuiltinType(PrimitiveType.Int)),
Name = GeneratedIdentifier("forBases")
});
}
}
return @params;
}
private IEnumerable<string> GatherInternalParams(Function function, out CSharpTypePrinterResult retType)
{
TypePrinter.PushContext(CSharpTypePrinterContextKind.Native);
@ -670,7 +569,7 @@ namespace CppSharp.Generators.CSharp @@ -670,7 +569,7 @@ namespace CppSharp.Generators.CSharp
var retParam = new Parameter { QualifiedType = function.ReturnType };
retType = retParam.CSharpType(TypePrinter);
var @params = GatherInternalParams(function).Select(p =>
var @params = function.GatherInternalParams(Driver.Options.IsItaniumLikeAbi).Select(p =>
string.Format("{0} {1}", p.CSharpType(TypePrinter), p.Name)).ToList();
TypePrinter.PopContext();
@ -722,7 +621,7 @@ namespace CppSharp.Generators.CSharp @@ -722,7 +621,7 @@ namespace CppSharp.Generators.CSharp
bases.AddRange(
from @base in @class.Bases
where @base.IsClass
select QualifiedIdentifierIfNeeded(@base.Class));
select @base.Class.Visit(TypePrinter).Type);
}
if (@class.IsGenerated)
@ -1602,18 +1501,14 @@ namespace CppSharp.Generators.CSharp @@ -1602,18 +1501,14 @@ namespace CppSharp.Generators.CSharp
WriteLine("// {0}", cleanSig);
}
WriteLine("[SuppressUnmanagedCodeSecurity]");
WriteLine("[UnmanagedFunctionPointerAttribute(global::System.Runtime.InteropServices.CallingConvention.{0})]",
method.CallingConvention.ToInteropCallConv());
CSharpTypePrinterResult retType;
var @params = GatherInternalParams(method, out retType);
var vTableMethodDelegateName = GetVTableMethodDelegateName(method);
WriteLine("internal delegate {0} {1}({2});", retType, vTableMethodDelegateName,
string.Join(", ", @params));
WriteLine("private static {0} {0}Instance;", vTableMethodDelegateName);
WriteLine("private static {0} {1}Instance;", DelegatesPass.Delegates[method].Visit(TypePrinter),
vTableMethodDelegateName);
NewLine();
WriteLine("private static {0} {1}Hook({2})", retType, vTableMethodDelegateName,
@ -1866,7 +1761,7 @@ namespace CppSharp.Generators.CSharp @@ -1866,7 +1761,7 @@ namespace CppSharp.Generators.CSharp
// The local var must be of the exact type in the object map because of TryRemove
WriteLine("{0} {1};",
QualifiedIdentifierIfNeeded(@interface ?? (@base.IsAbstractImpl ? @base.BaseClass : @base)),
(@interface ?? (@base.IsAbstractImpl ? @base.BaseClass : @base)).Visit(TypePrinter),
Helpers.DummyIdentifier);
WriteLine("NativeToManagedMap.TryRemove({0}, out {1});",
Helpers.InstanceIdentifier, Helpers.DummyIdentifier);
@ -1943,7 +1838,7 @@ namespace CppSharp.Generators.CSharp @@ -1943,7 +1838,7 @@ namespace CppSharp.Generators.CSharp
var hasBaseClass = @class.HasBaseClass && @class.BaseClass.IsRefType;
if (hasBaseClass)
WriteLineIndent(": base(({0}.Internal*) null)", QualifiedIdentifierIfNeeded(@class.BaseClass));
WriteLineIndent(": base(({0}.Internal*) null)", @class.BaseClass.Visit(TypePrinter));
WriteStartBraceIndent();
@ -2013,7 +1908,7 @@ namespace CppSharp.Generators.CSharp @@ -2013,7 +1908,7 @@ namespace CppSharp.Generators.CSharp
// Allocate memory for a new native object and call the ctor.
WriteLine("var ret = Marshal.AllocHGlobal({0});", @class.Layout.Size);
WriteLine("{0}.Internal.{1}(ret, new global::System.IntPtr(&native));",
QualifiedIdentifierIfNeeded(@class), GetFunctionNativeIdentifier(copyCtorMethod));
@class.Visit(TypePrinter), GetFunctionNativeIdentifier(copyCtorMethod));
WriteLine("return ({0}.Internal*) ret;", className);
}
else
@ -2391,8 +2286,8 @@ namespace CppSharp.Generators.CSharp @@ -2391,8 +2286,8 @@ namespace CppSharp.Generators.CSharp
delegateId = Generator.GeneratedIdentifier(@delegate);
virtualCallBuilder.AppendFormat(
"var {1} = ({0}) Marshal.GetDelegateForFunctionPointer(new IntPtr({2}), typeof({0}));",
@delegate, delegateId, Helpers.SlotIdentifier);
"var {0} = ({1}) Marshal.GetDelegateForFunctionPointer(new IntPtr({2}), typeof({1}));",
delegateId, DelegatesPass.Delegates[function].Visit(TypePrinter), Helpers.SlotIdentifier);
virtualCallBuilder.AppendLine();
return virtualCallBuilder.ToString();
@ -2533,7 +2428,7 @@ namespace CppSharp.Generators.CSharp @@ -2533,7 +2428,7 @@ namespace CppSharp.Generators.CSharp
if (construct == null)
{
WriteLine("var {0} = new {1}.Internal();", Helpers.ReturnIdentifier,
QualifiedIdentifierIfNeeded(retClass.OriginalClass ?? retClass));
(retClass.OriginalClass ?? retClass).Visit(TypePrinter));
}
else
{
@ -2777,8 +2672,7 @@ namespace CppSharp.Generators.CSharp @@ -2777,8 +2672,7 @@ namespace CppSharp.Generators.CSharp
Class @class;
if ((paramType.GetFinalPointee() ?? paramType).Desugar().TryGetClass(out @class))
{
var qualifiedIdentifier = CSharpMarshalNativeToManagedPrinter.QualifiedIdentifier(
@class.OriginalClass ?? @class);
var qualifiedIdentifier = (@class.OriginalClass ?? @class).Visit(TypePrinter);
WriteLine("{0} = new {1}();", name, qualifiedIdentifier);
}
}
@ -2865,7 +2759,8 @@ namespace CppSharp.Generators.CSharp @@ -2865,7 +2759,8 @@ namespace CppSharp.Generators.CSharp
var interopCallConv = callingConvention.ToInteropCallConv();
if (interopCallConv != System.Runtime.InteropServices.CallingConvention.Winapi)
WriteLine(
"[UnmanagedFunctionPointerAttribute(global::System.Runtime.InteropServices.CallingConvention.{0})]",
"[SuppressUnmanagedCodeSecurity, " +
"UnmanagedFunctionPointerAttribute(global::System.Runtime.InteropServices.CallingConvention.{0})]",
interopCallConv);
WriteLine("{0}unsafe {1};",
Helpers.GetAccess(typedef.Access),

4
src/Generator/Generators/CSharp/CSharpTypePrinter.cs

@ -589,7 +589,7 @@ namespace CppSharp.Generators.CSharp @@ -589,7 +589,7 @@ namespace CppSharp.Generators.CSharp
return GetNestedQualifiedName(@enum);
}
static private string GetNestedQualifiedName(Declaration decl)
private string GetNestedQualifiedName(Declaration decl)
{
var names = new List<string> { decl.Name };
@ -603,6 +603,8 @@ namespace CppSharp.Generators.CSharp @@ -603,6 +603,8 @@ namespace CppSharp.Generators.CSharp
}
names.Reverse();
if (names[0] == driver.Options.OutputNamespace)
names.RemoveAt(0);
return string.Join(".", names);
}

131
src/Generator/Passes/DelegatesPass.cs

@ -0,0 +1,131 @@ @@ -0,0 +1,131 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CppSharp.AST;
using CppSharp.AST.Extensions;
using CppSharp.Generators.CSharp;
namespace CppSharp.Passes
{
public class DelegatesPass : TranslationUnitPass
{
public const string DelegatesNamespace = "Delegates";
public DelegatesPass()
{
Options.VisitClassBases = false;
Options.VisitFunctionParameters = false;
Options.VisitFunctionReturnType = false;
Options.VisitNamespaceEnums = false;
Options.VisitNamespaceTemplates = false;
Options.VisitTemplateArguments = false;
}
public static Dictionary<Function, TypedefDecl> Delegates
{
get { return delegates; }
}
public override bool VisitLibrary(ASTContext context)
{
foreach (var library in Driver.Options.Libraries.Where(l => !libsDelegates.ContainsKey(l)))
libsDelegates.Add(library, new Dictionary<string, TypedefDecl>());
var unit = context.TranslationUnits.Last(u => u.IsValid && u.IsGenerated &&
!u.IsSystemHeader && u.HasDeclarations);
namespaceDelegates = new Namespace { Name = DelegatesNamespace, Namespace = unit };
var result = base.VisitLibrary(context);
if (namespaceDelegates.Declarations.Count > 0)
unit.Declarations.Add(namespaceDelegates);
return result;
}
public override bool VisitMethodDecl(Method method)
{
if (!base.VisitMethodDecl(method) || !method.IsVirtual || method.Ignore)
return false;
var @params = method.GatherInternalParams(Driver.Options.IsItaniumLikeAbi, true).ToList();
var delegateName = GenerateDelegateSignature(@params, method.ReturnType);
var existingDelegate = GetExistingDelegate(delegateName);
if (existingDelegate != null)
{
delegates.Add(method, existingDelegate);
return true;
}
var @delegate = new TypedefDecl
{
Name = delegateName,
QualifiedType = new QualifiedType(
new PointerType(
new QualifiedType(
new FunctionType
{
CallingConvention = method.CallingConvention,
IsDependent = method.IsDependent,
Parameters = @params,
ReturnType = method.ReturnType
}))),
Namespace = namespaceDelegates
};
delegates.Add(method, @delegate);
foreach (var library in Driver.Options.Libraries)
libsDelegates[library].Add(delegateName, @delegate);
namespaceDelegates.Declarations.Add(@delegate);
return true;
}
private TypedefDecl GetExistingDelegate(string delegateName)
{
TypedefDecl @delegate = null;
if (Driver.Options.Libraries.Count == 0)
return @delegates.Values.FirstOrDefault(v => v.Name == delegateName);
if (Driver.Options.Libraries.Union(Driver.Symbols.Libraries.SelectMany(l => l.Dependencies)).Any(
l => libsDelegates.ContainsKey(l) && libsDelegates[l].TryGetValue(delegateName, out @delegate)))
return @delegate;
return null;
}
private string GenerateDelegateSignature(IEnumerable<Parameter> @params, QualifiedType returnType)
{
var typePrinter = new CSharpTypePrinter(Driver);
typePrinter.PushContext(CSharpTypePrinterContextKind.Native);
var typesBuilder = new StringBuilder();
if (!returnType.Type.IsPrimitiveType(PrimitiveType.Void))
{
typesBuilder.Insert(0, returnType.Type.CSharpType(typePrinter));
typesBuilder.Append('_');
}
foreach (var parameter in @params)
{
typesBuilder.Append(parameter.CSharpType(typePrinter));
typesBuilder.Append('_');
}
if (typesBuilder.Length > 0)
typesBuilder.Remove(typesBuilder.Length - 1, 1);
var delegateName = typesBuilder.Replace("global::System.", string.Empty).Replace(
"*", "Ptr").Replace('.', '_').ToString();
if (returnType.Type.IsPrimitiveType(PrimitiveType.Void))
delegateName = "Action_" + delegateName;
else
delegateName = "Func_" + delegateName;
typePrinter.PopContext();
return delegateName;
}
private Namespace namespaceDelegates;
private static readonly Dictionary<string, Dictionary<string, TypedefDecl>> libsDelegates = new Dictionary<string, Dictionary<string, TypedefDecl>>();
private static readonly Dictionary<Function, TypedefDecl> delegates = new Dictionary<Function, TypedefDecl>();
}
}

2
src/Generator/Passes/RenameRootNamespaces.cs

@ -23,6 +23,8 @@ namespace CppSharp.Passes @@ -23,6 +23,8 @@ namespace CppSharp.Passes
}
else if (unit.GenerationKind == GenerationKind.Generate)
{
if (Driver.Options.IsCSharpGenerator)
unit.Name = Driver.Options.OutputNamespace;
rootNamespaceRenames.Add(fileName, Driver.Options.OutputNamespace);
}
return true;

Loading…
Cancel
Save