Tools and libraries to glue C/C++ APIs to high-level languages
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

365 lines
11 KiB

<#@ template language="C#" inherits="Base" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="Mono.Cxxi" #>
<#
var hasBase = Class.BaseClasses.Count > 0;
var wrapper = Class.Name;
var iface = "I" + Class.Name;
var layout = "_" + Class.Name;
var layoutClass = (hasBase? "\t: base (impl.TypeInfo)\n\t\t{" : "{") + "\n\t\t\t__cxxi_LayoutClass ();";
var initBases = (Class.BaseClasses.Count > 1 ? "\t__cxxi_InitBases ();\n\t\t}" : "}");
#>
// -------------------------------------------------------------------------
// Managed wrapper for <#= Class.Name #>
// Generated from <#= Path.GetFileName (Generator.InputFileName) #> on <#= DateTime.Now #>
//
// This file was auto generated. Do not edit.
// -------------------------------------------------------------------------
using System;
using Mono.Cxxi;
namespace <#= Generator.Namespace #> {
public partial class <#= wrapper #> : <#= GetBaseString () #> {
private static readonly <#= iface #> impl = Libs.<#= Generator.LibBaseName #>.GetClass<<#= iface + "," + layout + "," + wrapper #>> ("<#= Class.Name #>");
<# if (!hasBase) { #>
public CppInstancePtr Native { get; protected set; }
<# } #>
<# /* Interface */ #>
public interface <#= iface #> : ICppClassOverridable<<#= wrapper #>> {
<# PushIndent ("\t\t\t");
foreach (var method in Class.Methods) {
Write (CurrentIndent);
if (method.IsVirtual) Write ("[Virtual] ");
if (method.IsStatic) Write ("[Static] ");
if (method.IsArtificial) Write ("[Artificial] ");
if (method.IsInline) Write ("[Inline] ");
if (method.IsConst) Write ("[Const] ");
if (method.IsConstructor) Write ("[Constructor] ");
if (method.IsDestructor) Write ("[Destructor] ");
if (method.IsCopyCtor) Write ("[CopyConstructor] ");
if (IsByVal (method.ReturnType)) {
Write ("[return: ByVal] ");
}
if (method.IsConstructor)
Write ("CppInstancePtr");
else
Write (CSharpLanguage.TypeName (method.ReturnType, Context.Interface | Context.Return));
Write (" ");
Write (CSharpLanguage.SafeIdentifier (method.Name));
Write (" (");
if (!method.IsStatic) {
Write ("CppInstancePtr @this");
if (method.Parameters.Count != 0)
Write (", ");
}
WriteParameters (method.Parameters, true, !method.IsVirtual);
Write (");\n");
}
foreach (var field in Class.Fields.Where (f => f.Access != Access.@private)) {
WriteLine ("CppField<{0}> {1} {{ get; }}", CSharpLanguage.TypeName (field.Type, Context.Generic), CSharpLanguage.SafeIdentifier (field.Name));
}
ClearIndent (); #>
}
<# /* Native layout */ #>
private struct <#= layout #> {
<# foreach (var field in Class.Fields) { #>
public <#= CSharpLanguage.TypeName (field.Type, Context.Generic) #> <#= CSharpLanguage.SafeIdentifier (field.Name) #>;
<# } #>
}
<# /* Native fields */ #>
<# PushIndent ("\t\t");
foreach (var field in Class.Fields.Where (f => f.Access != Access.@private)) {
var fieldName = CSharpLanguage.SafeIdentifier (field.Name);
WriteLine ("{0} {1} {2} {{", field.Access, CSharpLanguage.TypeName (field.Type, Context.Wrapper | Context.Return), fieldName); #>
get {
return impl.<#= fieldName #> [Native];
}
set {
impl.<#= fieldName #> [Native] = value;
}
}
<# } ClearIndent(); #>
<# /* Subclass constructor */ #>
public <#= wrapper #> (CppTypeInfo subClass)
<#= layoutClass #>
subClass.AddBase (impl.TypeInfo);
<#= initBases #>
<# /* Native constructor */ #>
public <#= wrapper #> (CppInstancePtr native)
<#= layoutClass #>
Native = native;
<#= initBases #>
<# /* Wrapper methods */ #>
<# PushIndent ("\t\t");
foreach (var method in Class.Methods.Where (m => m.GenWrapperMethod)) {
var methodName = CSharpLanguage.SafeIdentifier (method.Name);
WriteMethodHeader (method, layoutClass, false, false);
if (method.IsConstructor)
Write ("Native = ");
Write ("impl.{0} (", methodName);
if (!method.IsStatic) {
if (method.IsConstructor)
Write ("impl.Alloc (this)");
else
Write ("Native");
if (method.Parameters.Count != 0)
Write (", ");
}
WriteParameters (method.Parameters, false, false);
Write (");\n");
PopIndent ();
if (method.IsConstructor)
WriteLine (initBases);
else
WriteLine ("}");
}
ClearIndent (); #>
<# /* Wrapper properties */ #>
<# PushIndent ("\t\t");
foreach (var prop in Class.Properties) {
var propName = CSharpLanguage.SafeIdentifier (prop.Name);
var type = CSharpLanguage.TypeName (prop.Type, Context.Wrapper | Context.Return);
Write (CurrentIndent + "public ");
if ((prop.GetMethod == null || prop.GetMethod.IsVirtual) &&
(prop.SetMethod == null || prop.SetMethod.IsVirtual))
Write ("virtual ");
Write (type);
Write (" ");
Write (propName);
Write (" {\n");
PushIndent ("\t");
Write (CurrentIndent);
if (prop.GetMethod != null) {
if (prop.GetMethod.IsVirtual)
Write ("[OverrideNative (\"{0}\")] ", prop.GetMethod.Name);
Write ("get {\n");
PushIndent ("\t");
WriteLine ("return impl.{0} (Native);", prop.GetMethod.Name);
PopIndent ();
WriteLine ("}");
}
if (prop.SetMethod != null) {
if (prop.SetMethod.IsVirtual)
Write ("[OverrideNative (\"{0}\")] ", prop.SetMethod.Name);
WriteLine ("set {");
PushIndent ("\t");
WriteLine ("impl.{0} (Native, value);", prop.SetMethod.Name);
PopIndent ();
WriteLine ("}");
}
PopIndent ();
WriteLine ("}\n");
}
ClearIndent (); #>
public <#= hasBase? "override" : "virtual" #> void Dispose ()
{
<# if (Class.Methods.Any (m => m.IsDestructor && !m.IsArtificial)) { #>
impl.Destruct (Native);
<# } #>
Native.Dispose ();
}
private void __cxxi_LayoutClass ()
{
<# foreach (var npBase in Class.BaseClasses.Skip (1)) { #>
new <#= npBase.Name #> (impl.TypeInfo);
<# } #>
impl.TypeInfo.CompleteType ();
}
<# /* Make this wrapper castable to non-primary bases */
foreach (var npBase in Class.BaseClasses.Skip (1)) { #>
#region Non-primary base class implementation for <#= npBase.Name #>
private class <#= wrapper + "__" + npBase.Name #> : <#= npBase.Name #> {
public <#= wrapper #> instance;
public <#= wrapper + "__" + npBase.Name #> (<#= wrapper #> instance)
: base (<#= wrapper #>.impl.TypeInfo.Cast (instance, typeof (<#= npBase.Name #>)))
{
<#= wrapper #>.impl.TypeInfo.InitNonPrimaryBase (this, instance, typeof (<#= npBase.Name #>));
this.instance = instance;
}
<# PushIndent ("\t\t\t");
foreach (var method in npBase.Methods.Where (m => m.IsVirtual)) {
if (!method.GenWrapperMethod || Class.Methods.Any (m => m.Node.CheckValue ("overrides", method.Node.Id)))
continue;
/* this is the managed override that has to call the subclass's method */
WriteMethodHeader (method, null, true, false);
Write ("instance.{0} (", npBase.Name + "__" + method.FormattedName);
WriteParameters (method.Parameters, false, false);
PopIndent ();
Write (");\n{0}}}\n\n", CurrentIndent);
/* this is the method that calls the base implementation that the subclass will use */
WriteMethodHeader (method, npBase.Name + "__" + method.FormattedName, true, false);
Write ("base.{0} (", method.FormattedName);
WriteParameters (method.Parameters, false, false);
PopIndent ();
Write (");\n{0}}}\n\n", CurrentIndent);
}
ClearIndent (); #>
}
private <#= wrapper #>__<#= npBase.Name #> __cxxi_<#= npBase.Name #>;
public <#= npBase.Name #> <#= npBase.Name #> { get { return __cxxi_<#= npBase.Name #>; } }
public static implicit operator <#= npBase.Name #>(<#= wrapper #> subClass)
{
return subClass.<#= npBase.Name #>;
}
public static explicit operator <#= wrapper #>(<#= npBase.Name #> baseClass)
{
if (baseClass == null) return null;
var obj = baseClass as <#= wrapper + "__" + npBase.Name #>;
if (obj == null) throw new InvalidCastException ();
return obj.instance;
}
<# /* Add virtual methods of non-primary bases to this class proper so they can be overridden */ #>
<# PushIndent ("\t\t");
foreach (var method in npBase.Methods.Where (m => m.IsVirtual)) {
if (!method.GenWrapperMethod || Class.Methods.Any (m => m.Node.CheckValue ("overrides", method.Node.Id)))
continue;
WriteMethodHeader (method, npBase.Name + "__" + method.FormattedName, true, true);
Write ("{0}.{1} (", "__cxxi_" + npBase.Name, npBase.Name + "__" + method.FormattedName);
WriteParameters (method.Parameters, false, false);
PopIndent ();
Write (");\n{0}}}\n\n", CurrentIndent);
}
ClearIndent ();
WriteLine ("#endregion");
}
if (Class.BaseClasses.Count > 1) { #>
private void __cxxi_InitBases ()
{
<# foreach (var npBase in Class.BaseClasses.Skip (1)) { #>
__cxxi_<#= npBase.Name #> = new <#= wrapper + "__" + npBase.Name #> (this);
<# } #>
}
<# } #>
}
}
<#+
private void WriteMethodHeader (Method method, string layoutClass, bool isNonPrimaryOverride, bool @protected)
{
var returnType = CSharpLanguage.TypeName (method.ReturnType, Context.Wrapper | Context.Return);
if (!isNonPrimaryOverride && method.IsVirtual)
WriteLine ("[OverrideNative (\"{0}\")]", method.Name);
Write (CurrentIndent + (@protected? "protected " : "public "));
if (method.IsConstructor) {
Write (method.FormattedName);
} else {
if (method.IsStatic) Write ("static ");
if (method.IsVirtual && (!isNonPrimaryOverride || layoutClass != null)) Write ("virtual ");
else if (isNonPrimaryOverride) Write ("override ");
// ...?
Write (returnType);
Write (" ");
Write (isNonPrimaryOverride && layoutClass != null? layoutClass : method.FormattedName);
}
Write (" (");
WriteParameters (method.Parameters, true, false);
Write (")\n");
if (method.IsConstructor && layoutClass != null)
WriteLine (layoutClass);
else
WriteLine ("{");
PushIndent ("\t");
Write (CurrentIndent);
if (returnType != "void")
Write ("return ");
}
private void WriteParameters (IList<Parameter> parameters, bool writeType, bool writeAttributes)
{
for (var i = 0; i < parameters.Count; i++) {
if (i != 0)
Write (", ");
var type = CSharpLanguage.TypeName (parameters [i].Type, Context.Parameter);
if (writeAttributes) {
var mangleAs = parameters [i].Type.ToString ();
if (mangleAs != "" && mangleAs != type)
Write ("[MangleAs (\"{0}\")] ", mangleAs);
if (IsByVal (parameters [i].Type))
Write ("[ByVal] ");
}
if (writeType) {
Write (type);
Write (" ");
} else {
if (type.StartsWith ("ref "))
Write ("ref ");
}
Write (CSharpLanguage.SafeIdentifier (parameters [i].Name));
}
}
private string GetBaseString ()
{
if (Class.BaseClasses.Count == 0)
return "ICppObject";
var str = Class.BaseClasses [0].Name;
if (Class.BaseClasses.Count > 1) {
str = string.Format ("{0} /*, {1} */", str, string.Join (", ", Class.BaseClasses.Skip (1).Select (bc => bc.Name).ToArray ()));
}
return str;
}
private bool IsByVal (CppType t)
{
return ((t.ElementType == CppTypes.Class || t.ElementType == CppTypes.Struct) &&
!t.Modifiers.Contains (CppModifiers.Pointer) &&
!t.Modifiers.Contains (CppModifiers.Reference) &&
!t.Modifiers.Contains (CppModifiers.Array));
}
#>