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.
 
 
 
 
 

516 lines
16 KiB

using System;
using System.Diagnostics;
using System.Globalization;
using System.Text;
using Cxxi.Types;
namespace Cxxi.Generators.CLI
{
public class CLIMarshalNativeToManagedPrinter : ITypeVisitor<bool>,
IDeclVisitor<bool>
{
public TextGenerator Support;
public TextGenerator Return;
Generator Generator { get; set; }
MarshalContext Context { get; set; }
public CLIMarshalNativeToManagedPrinter(Generator gen, MarshalContext ctx)
{
Generator = gen;
Context = ctx;
Support = new TextGenerator();
Return = new TextGenerator();
}
public bool VisitTagType(TagType tag, TypeQualifiers quals)
{
var decl = tag.Declaration;
return decl.Visit(this);
}
public bool VisitArrayType(ArrayType array, TypeQualifiers quals)
{
return false;
}
public bool VisitFunctionType(FunctionType function, TypeQualifiers quals)
{
var returnType = function.ReturnType;
return returnType.Visit(this, quals);
}
public bool VisitPointerType(PointerType pointer, TypeQualifiers quals)
{
var pointee = pointer.Pointee;
if (pointee.IsPrimitiveType(PrimitiveType.Void))
{
Return.Write("IntPtr()");
return true;
}
if (pointee.IsPrimitiveType(PrimitiveType.Char))
{
Return.Write("clix::marshalString<clix::E_UTF8>({0})",
Context.ReturnVarName);
return true;
}
PrimitiveType primitive;
if (pointee.IsPrimitiveType(out primitive, walkTypedefs: true))
Return.Write("*");
if (!pointee.Visit(this, quals))
return false;
return true;
}
public bool VisitMemberPointerType(MemberPointerType member,
TypeQualifiers quals)
{
return false;
}
public bool VisitBuiltinType(BuiltinType builtin, TypeQualifiers quals)
{
return VisitPrimitiveType(builtin.Type);
}
public bool VisitPrimitiveType(PrimitiveType primitive)
{
switch (primitive)
{
case PrimitiveType.Void:
return true;
case PrimitiveType.Bool:
case PrimitiveType.Int8:
case PrimitiveType.UInt8:
case PrimitiveType.Int16:
case PrimitiveType.UInt16:
case PrimitiveType.Int32:
case PrimitiveType.UInt32:
case PrimitiveType.Int64:
case PrimitiveType.UInt64:
case PrimitiveType.Float:
case PrimitiveType.Double:
Return.Write(Context.ReturnVarName);
return true;
case PrimitiveType.WideChar:
return false;
}
return false;
}
public bool VisitTypedefType(TypedefType typedef, TypeQualifiers quals)
{
var decl = typedef.Declaration;
TypeMap typeMap = null;
if (Generator.TypeMapDatabase.FindTypeMap(decl, out typeMap))
{
Return.Write(typeMap.MarshalFromNative(Context));
return typeMap.IsValueType;
}
// TODO: How should function pointers behave here?
return decl.Type.Visit(this);
}
public bool VisitTemplateSpecializationType(TemplateSpecializationType template,
TypeQualifiers quals)
{
return template.Template.Visit(this);
}
public bool VisitDeclaration(Declaration decl, TypeQualifiers quals)
{
throw new NotImplementedException();
}
public bool VisitDeclaration(Declaration decl)
{
throw new NotImplementedException();
}
public bool VisitClassDecl(Class @class)
{
if (@class.IsRefType)
Return.Write("gcnew ");
Return.Write("{0}::{1}(", Generator.Library.Name,
@class.Name);
Return.Write("(::{0}*)", @class.QualifiedOriginalName);
if (@class.IsValueType && !this.Context.ReturnType.IsPointer())
Return.Write("&");
Return.Write("{0})", this.Context.ReturnVarName);
return true;
}
public bool VisitFieldDecl(Field field)
{
throw new NotImplementedException();
}
public bool VisitFunctionDecl(Function function)
{
throw new NotImplementedException();
}
public bool VisitMethodDecl(Method method)
{
throw new NotImplementedException();
}
public bool VisitParameterDecl(Parameter parameter)
{
throw new NotImplementedException();
}
public bool VisitTypedefDecl(TypedefDecl typedef)
{
throw new NotImplementedException();
}
public bool VisitEnumDecl(Enumeration @enum)
{
Return.Write("({0}){1}", ToCLITypeName(@enum),
Context.ReturnVarName);
return true;
}
private string ToCLITypeName(Declaration decl)
{
var typePrinter = new CLITypePrinter(Generator);
return typePrinter.VisitDeclaration(decl);
}
public bool VisitClassTemplateDecl(ClassTemplate template)
{
return template.TemplatedClass.Visit(this);
}
public bool VisitFunctionTemplateDecl(FunctionTemplate template)
{
throw new NotImplementedException();
}
public bool VisitMacroDefinition(MacroDefinition macro)
{
throw new NotImplementedException();
}
public bool VisitNamespace(Namespace @namespace)
{
throw new NotImplementedException();
}
public bool VisitDelegate(Delegate @delegate)
{
throw new NotImplementedException();
}
}
public class CLIMarshalManagedToNativePrinter : ITypeVisitor<bool>,
IDeclVisitor<bool>
{
public TextGenerator SupportBefore;
public TextGenerator SupportAfter;
public TextGenerator Return;
public TextGenerator ArgumentPrefix;
Generator Generator { get; set; }
MarshalContext Context { get; set; }
public CLIMarshalManagedToNativePrinter(Generator gen, MarshalContext ctx)
{
Generator = gen;
Context = ctx;
SupportBefore = new TextGenerator();
SupportAfter = new TextGenerator();
Return = new TextGenerator();
ArgumentPrefix = new TextGenerator();
}
public bool VisitTagType(TagType tag, TypeQualifiers quals)
{
var decl = tag.Declaration;
return decl.Visit(this);
}
public bool VisitArrayType(ArrayType array, TypeQualifiers quals)
{
return false;
}
public bool VisitFunctionType(FunctionType function, TypeQualifiers quals)
{
var returnType = function.ReturnType;
return returnType.Visit(this, quals);
}
public bool VisitDelegateType(FunctionType function, string type)
{
// We marshal function pointer types by calling
// GetFunctionPointerForDelegate to get a native function
// pointer ouf of the delegate. Then we can pass it in the
// native call. Since references are not tracked in the
// native side, we need to be careful and protect it with an
// explicit GCHandle if necessary.
var sb = new StringBuilder();
sb.AppendFormat("static_cast<::{0}>(", type);
sb.Append("System::Runtime::InteropServices::Marshal::");
sb.Append("GetFunctionPointerForDelegate(");
sb.AppendFormat("{0}).ToPointer())", Context.Parameter.Name);
Return.Write(sb.ToString());
return true;
}
public bool VisitPointerType(PointerType pointer, TypeQualifiers quals)
{
var pointee = pointer.Pointee;
var isVoidPtr = pointee.IsPrimitiveType(PrimitiveType.Void,
walkTypedefs: true);
var isUInt8Ptr = pointee.IsPrimitiveType(PrimitiveType.UInt8,
walkTypedefs: true);
if (isVoidPtr || isUInt8Ptr)
{
if (isUInt8Ptr)
Return.Write("({0})", "uint8*");
Return.Write("{0}.ToPointer()", Context.Parameter.Name);
return true;
}
if (pointee.IsPrimitiveType(PrimitiveType.Char))
{
SupportBefore.Write(
"auto _{0} = clix::marshalString<clix::E_UTF8>({1});",
Context.ArgName, Context.Parameter.Name);
Return.Write("_{0}.c_str()", Context.ArgName);
return true;
}
if (pointee is FunctionType)
{
var function = pointee as FunctionType;
// TODO: We have to translate the function type typedef to C/C++
return VisitDelegateType(function, function.ToString());
}
return pointee.Visit(this, quals);
}
public bool VisitMemberPointerType(MemberPointerType member,
TypeQualifiers quals)
{
return false;
}
public bool VisitBuiltinType(BuiltinType builtin, TypeQualifiers quals)
{
return VisitPrimitiveType(builtin.Type);
}
public bool VisitPrimitiveType(PrimitiveType primitive)
{
switch (primitive)
{
case PrimitiveType.Void:
return true;
case PrimitiveType.Bool:
case PrimitiveType.Int8:
case PrimitiveType.UInt8:
case PrimitiveType.Int16:
case PrimitiveType.UInt16:
case PrimitiveType.Int32:
case PrimitiveType.UInt32:
case PrimitiveType.Int64:
case PrimitiveType.UInt64:
case PrimitiveType.Float:
case PrimitiveType.Double:
Return.Write(Context.Parameter.Name);
return true;
case PrimitiveType.WideChar:
return false;
}
return false;
}
public bool VisitTypedefType(TypedefType typedef, TypeQualifiers quals)
{
var decl = typedef.Declaration;
TypeMap typeMap = null;
if (Generator.TypeMapDatabase.FindTypeMap(decl, out typeMap))
{
Return.Write(typeMap.MarshalToNative(Context));
return typeMap.IsValueType;
}
FunctionType func;
if (decl.Type.IsPointerTo<FunctionType>(out func))
{
VisitDelegateType(func, typedef.Declaration.OriginalName);
return true;
}
PrimitiveType primitive;
if (decl.Type.IsPrimitiveType(out primitive, walkTypedefs: true))
{
Return.Write("({0})", typedef.Declaration.Name);
}
return decl.Type.Visit(this);
}
public bool VisitTemplateSpecializationType(TemplateSpecializationType template,
TypeQualifiers quals)
{
return template.Template.Visit(this);
}
public bool VisitDeclaration(Declaration decl, TypeQualifiers quals)
{
throw new NotImplementedException();
}
public bool VisitDeclaration(Declaration decl)
{
throw new NotImplementedException();
}
public bool VisitClassDecl(Class @class)
{
if (@class.IsValueType)
{
if (Context.Parameter.Type.IsReference())
{
var argName = string.Format("_{0}", Context.ArgName);
SupportBefore.Write("auto {0} = (::{1}*)&{2};",
argName, @class.OriginalName,
Context.Parameter.Name);
Return.Write("*{0}", argName);
}
else
{
SupportAfter.PushIndent();
foreach (var field in @class.Fields)
{
SupportAfter.Write("{0}.{1} = ", Context.ArgName,
field.OriginalName);
var fieldRef = string.Format("{0}.{1}", Context.Parameter.Name,
field.Name);
var marshalCtx = new MarshalContext() { ArgName = fieldRef };
var marshal = new CLIMarshalManagedToNativePrinter(Generator,
marshalCtx);
field.Visit(marshal);
SupportAfter.WriteLine("{0};", marshal.Return);
}
Return.Write("::{0}()", @class.QualifiedOriginalName);
if (Context.Parameter.Type.IsPointer())
ArgumentPrefix.Write("&");
}
}
else
{
if (!Context.Parameter.Type.IsPointer())
Return.Write("*");
var method = Context.Function as Method;
if (method != null
&& method.Conversion == MethodConversionType.FunctionToInstanceMethod
&& Context.ParameterIndex == 0)
{
Return.Write("NativePtr");
return true;
}
Return.Write("{0}->NativePtr", Context.Parameter.Name);
}
return true;
}
public bool VisitFieldDecl(Field field)
{
Context.Parameter = new Parameter
{
Name = Context.ArgName, Type = field.Type
};
return field.Type.Visit(this);
}
public bool VisitFunctionDecl(Function function)
{
throw new NotImplementedException();
}
public bool VisitMethodDecl(Method method)
{
throw new NotImplementedException();
}
public bool VisitParameterDecl(Parameter parameter)
{
return parameter.Type.Visit(this);
}
public bool VisitTypedefDecl(TypedefDecl typedef)
{
throw new NotImplementedException();
}
public bool VisitEnumDecl(Enumeration @enum)
{
Return.Write("(::{0}){1}", @enum.QualifiedOriginalName,
Context.Parameter.Name);
return true;
}
public bool VisitClassTemplateDecl(ClassTemplate template)
{
return template.TemplatedClass.Visit(this);
}
public bool VisitFunctionTemplateDecl(FunctionTemplate template)
{
throw new NotImplementedException();
}
public bool VisitMacroDefinition(MacroDefinition macro)
{
throw new NotImplementedException();
}
public bool VisitNamespace(Namespace @namespace)
{
throw new NotImplementedException();
}
public bool VisitDelegate(Delegate @delegate)
{
throw new NotImplementedException();
}
}
}