mirror of https://github.com/mono/CppSharp.git
8 changed files with 2188 additions and 13 deletions
@ -0,0 +1,48 @@ |
|||||||
|
using System.Collections.Generic; |
||||||
|
using CppSharp.AST; |
||||||
|
using CppSharp.Generators.C; |
||||||
|
|
||||||
|
namespace CppSharp.Generators.Cpp |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// C/C++ generator responsible for driving the generation of source
|
||||||
|
/// and header files.
|
||||||
|
/// </summary>
|
||||||
|
public class CppGenerator : Generator |
||||||
|
{ |
||||||
|
private readonly CppTypePrinter typePrinter; |
||||||
|
|
||||||
|
public CppGenerator(BindingContext context) : base(context) |
||||||
|
{ |
||||||
|
typePrinter = new CppTypePrinter(); |
||||||
|
} |
||||||
|
|
||||||
|
public override List<CodeGenerator> Generate(IEnumerable<TranslationUnit> units) |
||||||
|
{ |
||||||
|
var outputs = new List<CodeGenerator>(); |
||||||
|
|
||||||
|
var header = new CppHeaders(Context, units); |
||||||
|
outputs.Add(header); |
||||||
|
|
||||||
|
var source = new CppSources(Context, units); |
||||||
|
outputs.Add(source); |
||||||
|
|
||||||
|
return outputs; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool SetupPasses() => true; |
||||||
|
|
||||||
|
public static bool ShouldGenerateClassNativeField(Class @class) |
||||||
|
{ |
||||||
|
if (@class.IsStatic) |
||||||
|
return false; |
||||||
|
|
||||||
|
return @class.IsRefType && (!@class.HasBase || !@class.HasRefBase()); |
||||||
|
} |
||||||
|
|
||||||
|
protected override string TypePrinterDelegate(Type type) |
||||||
|
{ |
||||||
|
return type.Visit(typePrinter).ToString(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,609 @@ |
|||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Linq; |
||||||
|
using CppSharp.AST; |
||||||
|
using CppSharp.AST.Extensions; |
||||||
|
using CppSharp.Generators.C; |
||||||
|
using CppSharp.Generators.CLI; |
||||||
|
|
||||||
|
namespace CppSharp.Generators.Cpp |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Generates C/C++ header files.
|
||||||
|
/// </summary>
|
||||||
|
public class CppHeaders : CCodeGenerator |
||||||
|
{ |
||||||
|
public CppHeaders(BindingContext context, IEnumerable<TranslationUnit> units) |
||||||
|
: base(context, units) |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
public override string FileExtension => "h"; |
||||||
|
|
||||||
|
public override void Process() |
||||||
|
{ |
||||||
|
GenerateFilePreamble(CommentKind.BCPL); |
||||||
|
|
||||||
|
PushBlock(BlockKind.Includes); |
||||||
|
WriteLine("#pragma once"); |
||||||
|
NewLine(); |
||||||
|
|
||||||
|
if (Options.OutputInteropIncludes) |
||||||
|
WriteLine("#include \"CppSharp.h\""); |
||||||
|
|
||||||
|
// Generate #include forward references.
|
||||||
|
PushBlock(BlockKind.IncludesForwardReferences); |
||||||
|
WriteLine("#include <{0}>", TranslationUnit.IncludePath); |
||||||
|
GenerateIncludeForwardRefs(); |
||||||
|
PopBlock(NewLineKind.BeforeNextBlock); |
||||||
|
PopBlock(NewLineKind.Always); |
||||||
|
|
||||||
|
// Generate namespace for forward references.
|
||||||
|
PushBlock(BlockKind.ForwardReferences); |
||||||
|
GenerateForwardRefs(); |
||||||
|
PopBlock(NewLineKind.BeforeNextBlock); |
||||||
|
|
||||||
|
VisitNamespace(TranslationUnit); |
||||||
|
|
||||||
|
PushBlock(BlockKind.Footer); |
||||||
|
PopBlock(); |
||||||
|
} |
||||||
|
|
||||||
|
public void GenerateIncludeForwardRefs() |
||||||
|
{ |
||||||
|
var typeReferenceCollector = new CLITypeReferenceCollector(Context.TypeMaps, |
||||||
|
Context.Options); |
||||||
|
typeReferenceCollector.Process(TranslationUnit, filterNamespaces: false); |
||||||
|
|
||||||
|
var includes = new SortedSet<string>(StringComparer.InvariantCulture); |
||||||
|
|
||||||
|
foreach (var typeRef in typeReferenceCollector.TypeReferences) |
||||||
|
{ |
||||||
|
if (typeRef.Include.TranslationUnit == TranslationUnit) |
||||||
|
continue; |
||||||
|
|
||||||
|
if (typeRef.Include.File == TranslationUnit.FileName) |
||||||
|
continue; |
||||||
|
|
||||||
|
var include = typeRef.Include; |
||||||
|
var unit = include.TranslationUnit; |
||||||
|
|
||||||
|
if (unit != null && !unit.IsDeclared) |
||||||
|
continue; |
||||||
|
|
||||||
|
if(!string.IsNullOrEmpty(include.File) && include.InHeader) |
||||||
|
includes.Add(include.ToString()); |
||||||
|
} |
||||||
|
|
||||||
|
foreach (var include in includes) |
||||||
|
WriteLine(include); |
||||||
|
} |
||||||
|
|
||||||
|
private Namespace FindCreateNamespace(Namespace @namespace, Declaration decl) |
||||||
|
{ |
||||||
|
if (decl.Namespace is TranslationUnit) |
||||||
|
return @namespace; |
||||||
|
|
||||||
|
var childNamespaces = decl.Namespace.GatherParentNamespaces(); |
||||||
|
var currentNamespace = @namespace; |
||||||
|
|
||||||
|
foreach (var child in childNamespaces) |
||||||
|
currentNamespace = currentNamespace.FindCreateNamespace(child.Name); |
||||||
|
|
||||||
|
return currentNamespace; |
||||||
|
} |
||||||
|
|
||||||
|
public Namespace ConvertForwardReferencesToNamespaces( |
||||||
|
IEnumerable<CLITypeReference> typeReferences) |
||||||
|
{ |
||||||
|
// Create a new tree of namespaces out of the type references found.
|
||||||
|
var rootNamespace = new TranslationUnit(); |
||||||
|
rootNamespace.Module = TranslationUnit.Module; |
||||||
|
|
||||||
|
var sortedRefs = typeReferences.ToList(); |
||||||
|
sortedRefs.Sort((ref1, ref2) => |
||||||
|
string.CompareOrdinal(ref1.FowardReference, ref2.FowardReference)); |
||||||
|
|
||||||
|
var forwardRefs = new SortedSet<string>(); |
||||||
|
|
||||||
|
foreach (var typeRef in sortedRefs) |
||||||
|
{ |
||||||
|
if (string.IsNullOrWhiteSpace(typeRef.FowardReference)) |
||||||
|
continue; |
||||||
|
|
||||||
|
var declaration = typeRef.Declaration; |
||||||
|
|
||||||
|
var isIncomplete = declaration.IsIncomplete && declaration.CompleteDeclaration == null; |
||||||
|
if (!declaration.IsGenerated || isIncomplete) |
||||||
|
continue; |
||||||
|
|
||||||
|
if (!(declaration.Namespace is Namespace)) |
||||||
|
continue; |
||||||
|
|
||||||
|
if (!forwardRefs.Add(typeRef.FowardReference)) |
||||||
|
continue; |
||||||
|
|
||||||
|
if (typeRef.Include.InHeader) |
||||||
|
continue; |
||||||
|
|
||||||
|
var @namespace = FindCreateNamespace(rootNamespace, declaration); |
||||||
|
@namespace.TypeReferences.Add(typeRef); |
||||||
|
} |
||||||
|
|
||||||
|
return rootNamespace; |
||||||
|
} |
||||||
|
|
||||||
|
public void GenerateForwardRefs() |
||||||
|
{ |
||||||
|
var typeReferenceCollector = new CLITypeReferenceCollector(Context.TypeMaps, |
||||||
|
Context.Options); |
||||||
|
typeReferenceCollector.Process(TranslationUnit); |
||||||
|
|
||||||
|
var typeReferences = typeReferenceCollector.TypeReferences; |
||||||
|
var @namespace = ConvertForwardReferencesToNamespaces(typeReferences); |
||||||
|
|
||||||
|
@namespace.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public void GenerateDeclContext(DeclarationContext decl) |
||||||
|
{ |
||||||
|
// Generate all the type references for the module.
|
||||||
|
foreach (var typeRef in decl.TypeReferences) |
||||||
|
{ |
||||||
|
WriteLine(typeRef.FowardReference); |
||||||
|
} |
||||||
|
|
||||||
|
// Generate all the enum declarations for the module.
|
||||||
|
foreach (var @enum in decl.Enums) |
||||||
|
{ |
||||||
|
if (!@enum.IsGenerated || @enum.IsIncomplete) |
||||||
|
continue; |
||||||
|
|
||||||
|
@enum.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
// Generate all the typedef declarations for the module.
|
||||||
|
GenerateTypedefs(decl); |
||||||
|
|
||||||
|
// Generate all the struct/class declarations for the module.
|
||||||
|
foreach (var @class in decl.Classes) |
||||||
|
{ |
||||||
|
@class.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
if (decl.Functions.Any(f => f.IsGenerated)) |
||||||
|
GenerateFunctions(decl); |
||||||
|
|
||||||
|
foreach (var childNamespace in decl.Namespaces) |
||||||
|
childNamespace.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitNamespace(Namespace @namespace) |
||||||
|
{ |
||||||
|
var isTopLevel = @namespace is TranslationUnit; |
||||||
|
var generateNamespace = !isTopLevel || |
||||||
|
!string.IsNullOrEmpty(@namespace.TranslationUnit.Module.OutputNamespace); |
||||||
|
|
||||||
|
if (generateNamespace) |
||||||
|
{ |
||||||
|
PushBlock(BlockKind.Namespace, @namespace); |
||||||
|
WriteLine("namespace {0}", isTopLevel |
||||||
|
? @namespace.TranslationUnit.Module.OutputNamespace |
||||||
|
: @namespace.Name); |
||||||
|
WriteOpenBraceAndIndent(); |
||||||
|
} |
||||||
|
|
||||||
|
GenerateDeclContext(@namespace); |
||||||
|
|
||||||
|
if (generateNamespace) |
||||||
|
{ |
||||||
|
UnindentAndWriteCloseBrace(); |
||||||
|
PopBlock(NewLineKind.BeforeNextBlock); |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public virtual void GenerateTypedefs(DeclarationContext decl) |
||||||
|
{ |
||||||
|
foreach (var typedef in decl.Typedefs) |
||||||
|
{ |
||||||
|
if (!typedef.IsGenerated) |
||||||
|
continue; |
||||||
|
|
||||||
|
typedef.Visit(this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public virtual void GenerateFunctions(DeclarationContext decl) |
||||||
|
{ |
||||||
|
PushBlock(BlockKind.FunctionsClass); |
||||||
|
|
||||||
|
// Generate all the function declarations for the module.
|
||||||
|
foreach (var function in decl.Functions) |
||||||
|
{ |
||||||
|
if (!function.IsGenerated) |
||||||
|
continue; |
||||||
|
|
||||||
|
function.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
PopBlock(NewLineKind.BeforeNextBlock); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitClassDecl(Class @class) |
||||||
|
{ |
||||||
|
if (!@class.IsGenerated || @class.IsIncomplete || @class.IsDependent) |
||||||
|
return false; |
||||||
|
|
||||||
|
//if (@class.IsOpaque)
|
||||||
|
// return false;
|
||||||
|
|
||||||
|
PushBlock(BlockKind.Class, @class); |
||||||
|
|
||||||
|
GenerateDeclarationCommon(@class); |
||||||
|
|
||||||
|
GenerateClassSpecifier(@class); |
||||||
|
|
||||||
|
if (@class.IsOpaque) |
||||||
|
{ |
||||||
|
WriteLine(";"); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
NewLine(); |
||||||
|
WriteLine("{"); |
||||||
|
WriteLine("public:"); |
||||||
|
NewLine(); |
||||||
|
|
||||||
|
// Process the nested types.
|
||||||
|
Indent(); |
||||||
|
GenerateDeclContext(@class); |
||||||
|
Unindent(); |
||||||
|
|
||||||
|
var nativeType = $"::{@class.QualifiedOriginalName}*"; |
||||||
|
|
||||||
|
if (CppGenerator.ShouldGenerateClassNativeField(@class)) |
||||||
|
GenerateClassNativeField(@class, nativeType); |
||||||
|
|
||||||
|
GenerateClassConstructors(@class, nativeType); |
||||||
|
GenerateClassProperties(@class); |
||||||
|
GenerateClassEvents(@class); |
||||||
|
GenerateClassMethods(@class.Methods); |
||||||
|
|
||||||
|
if (Options.GenerateFunctionTemplates) |
||||||
|
GenerateClassGenericMethods(@class); |
||||||
|
|
||||||
|
GenerateClassVariables(@class); |
||||||
|
|
||||||
|
if (CppGenerator.ShouldGenerateClassNativeField(@class)) |
||||||
|
{ |
||||||
|
PushBlock(BlockKind.AccessSpecifier); |
||||||
|
WriteLine("protected:"); |
||||||
|
PopBlock(NewLineKind.IfNotEmpty); |
||||||
|
|
||||||
|
PushBlock(BlockKind.Fields); |
||||||
|
WriteLineIndent($"bool {Helpers.OwnsNativeInstanceIdentifier};"); |
||||||
|
PopBlock(); |
||||||
|
} |
||||||
|
|
||||||
|
PushBlock(BlockKind.AccessSpecifier); |
||||||
|
WriteLine("private:"); |
||||||
|
var accBlock = PopBlock(NewLineKind.IfNotEmpty); |
||||||
|
|
||||||
|
PushBlock(BlockKind.Fields); |
||||||
|
GenerateClassFields(@class); |
||||||
|
var fieldsBlock = PopBlock(); |
||||||
|
accBlock.CheckGenerate = () => !fieldsBlock.IsEmpty; |
||||||
|
|
||||||
|
WriteLine("};"); |
||||||
|
|
||||||
|
PopBlock(NewLineKind.BeforeNextBlock); |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public void GenerateClassNativeField(Class @class, string nativeType) |
||||||
|
{ |
||||||
|
var nativeInstanceField = new Field() |
||||||
|
{ |
||||||
|
Name = Helpers.InstanceIdentifier, |
||||||
|
QualifiedType = new QualifiedType(new PointerType(new QualifiedType(new TagType(@class)))), |
||||||
|
Namespace = @class |
||||||
|
}; |
||||||
|
|
||||||
|
Indent(); |
||||||
|
nativeInstanceField.Visit(this); |
||||||
|
Unindent(); |
||||||
|
|
||||||
|
/*var nativeInstanceProperty = new Property() |
||||||
|
{ |
||||||
|
Name = Helpers.InstanceIdentifier, |
||||||
|
QualifiedType = |
||||||
|
}; |
||||||
|
|
||||||
|
nativeInstanceProperty.Visit(this);*/ |
||||||
|
} |
||||||
|
|
||||||
|
public virtual void GenerateClassGenericMethods(Class @class) |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
public void GenerateClassConstructors(Class @class, string nativeType) |
||||||
|
{ |
||||||
|
if (@class.IsStatic) |
||||||
|
return; |
||||||
|
|
||||||
|
Indent(); |
||||||
|
|
||||||
|
var classNativeName = @class.Visit(CTypePrinter); |
||||||
|
|
||||||
|
CTypePrinter.PushContext(TypePrinterContextKind.Native); |
||||||
|
var classManagedName = @class.Visit(CTypePrinter); |
||||||
|
CTypePrinter.PopContext(); |
||||||
|
|
||||||
|
WriteLine($"{@class.Name}({classManagedName}* native);"); |
||||||
|
NewLine(); |
||||||
|
|
||||||
|
foreach (var ctor in @class.Constructors) |
||||||
|
{ |
||||||
|
if (ASTUtils.CheckIgnoreMethod(ctor) || FunctionIgnored(ctor)) |
||||||
|
continue; |
||||||
|
|
||||||
|
ctor.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
if (@class.IsRefType) |
||||||
|
{ |
||||||
|
var destructor = @class.Destructors |
||||||
|
.FirstOrDefault(d => d.Parameters.Count == 0 && d.Access == AccessSpecifier.Public); |
||||||
|
|
||||||
|
if (destructor != null) |
||||||
|
{ |
||||||
|
GenerateClassDestructor(@class); |
||||||
|
if (Options.GenerateFinalizers) |
||||||
|
GenerateClassFinalizer(@class); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Unindent(); |
||||||
|
} |
||||||
|
|
||||||
|
public virtual void GenerateClassDestructor(Class @class) |
||||||
|
{ |
||||||
|
PushBlock(BlockKind.Destructor); |
||||||
|
WriteLine($"~{@class.Name}();"); |
||||||
|
PopBlock(NewLineKind.BeforeNextBlock); |
||||||
|
} |
||||||
|
|
||||||
|
public void GenerateClassFinalizer(Class @class) |
||||||
|
{ |
||||||
|
PushBlock(BlockKind.Finalizer); |
||||||
|
WriteLine($"!{@class.Name}();"); |
||||||
|
PopBlock(NewLineKind.BeforeNextBlock); |
||||||
|
} |
||||||
|
|
||||||
|
public void GenerateClassFields(Class @class) |
||||||
|
{ |
||||||
|
// Handle the case of struct (value-type) inheritance by adding the base
|
||||||
|
// properties to the managed value subtypes.
|
||||||
|
if (@class.IsValueType) |
||||||
|
{ |
||||||
|
foreach (var @base in @class.Bases.Where(b => b.IsClass && b.Class.IsDeclared)) |
||||||
|
{ |
||||||
|
GenerateClassFields(@base.Class); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Indent(); |
||||||
|
// check for value types because some of the ignored fields may back properties;
|
||||||
|
// not the case for ref types because the NativePtr pattern is used there
|
||||||
|
foreach (var field in @class.Fields.Where(f => !ASTUtils.CheckIgnoreField(f))) |
||||||
|
{ |
||||||
|
var property = @class.Properties.FirstOrDefault(p => p.Field == field); |
||||||
|
if (property != null && !property.IsInRefTypeAndBackedByValueClassField()) |
||||||
|
{ |
||||||
|
field.Visit(this); |
||||||
|
} |
||||||
|
} |
||||||
|
Unindent(); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitFieldDecl(Field field) |
||||||
|
{ |
||||||
|
PushBlock(BlockKind.Field, field); |
||||||
|
|
||||||
|
GenerateDeclarationCommon(field); |
||||||
|
|
||||||
|
var @class = field.Namespace as Class; |
||||||
|
WriteLine($"{field.Type} {field.Name};"); |
||||||
|
|
||||||
|
PopBlock(); |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public void GenerateClassEvents(Class @class) |
||||||
|
{ |
||||||
|
foreach (var @event in @class.Events) |
||||||
|
{ |
||||||
|
if (!@event.IsGenerated) continue; |
||||||
|
@event.Visit(this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitEvent(Event @event) |
||||||
|
{ |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public void GenerateClassMethods(List<Method> methods) |
||||||
|
{ |
||||||
|
if (methods.Count == 0) |
||||||
|
return; |
||||||
|
|
||||||
|
Indent(); |
||||||
|
|
||||||
|
var @class = (Class) methods[0].Namespace; |
||||||
|
|
||||||
|
if (@class.IsValueType) |
||||||
|
foreach (var @base in @class.Bases.Where(b => b.IsClass && !b.Class.Ignore)) |
||||||
|
GenerateClassMethods(@base.Class.Methods.Where(m => !m.IsOperator).ToList()); |
||||||
|
|
||||||
|
var staticMethods = new List<Method>(); |
||||||
|
foreach (var method in methods) |
||||||
|
{ |
||||||
|
if (ASTUtils.CheckIgnoreMethod(method) || FunctionIgnored(method)) |
||||||
|
continue; |
||||||
|
|
||||||
|
if (method.IsConstructor) |
||||||
|
continue; |
||||||
|
|
||||||
|
if (method.IsStatic) |
||||||
|
{ |
||||||
|
staticMethods.Add(method); |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
method.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
foreach(var method in staticMethods) |
||||||
|
method.Visit(this); |
||||||
|
|
||||||
|
Unindent(); |
||||||
|
} |
||||||
|
|
||||||
|
public void GenerateClassVariables(Class @class) |
||||||
|
{ |
||||||
|
foreach (var variable in @class.Variables) |
||||||
|
{ |
||||||
|
if (!variable.IsGenerated) continue; |
||||||
|
variable.Visit(this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public override void GenerateClassSpecifier(Class @class) |
||||||
|
{ |
||||||
|
Write(@class.IsValueType ? "struct " : "class "); |
||||||
|
Write($"{@class.Name}"); |
||||||
|
|
||||||
|
if (@class.IsStatic) |
||||||
|
Write(" abstract sealed"); |
||||||
|
|
||||||
|
if (!@class.IsStatic && @class.HasRefBase()) |
||||||
|
Write($" : public {QualifiedIdentifier(@class.Bases[0].Class)}"); |
||||||
|
} |
||||||
|
|
||||||
|
public void GenerateClassProperties(Class @class) |
||||||
|
{ |
||||||
|
// Handle the case of struct (value-type) inheritance by adding the base
|
||||||
|
// properties to the managed value subtypes.
|
||||||
|
if (@class.IsValueType) |
||||||
|
{ |
||||||
|
foreach (var @base in @class.Bases.Where(b => b.IsClass && b.Class.IsDeclared)) |
||||||
|
{ |
||||||
|
GenerateClassProperties(@base.Class); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Indent(); |
||||||
|
foreach (var prop in @class.Properties.Where( |
||||||
|
prop => !ASTUtils.CheckIgnoreProperty(prop) && !TypeIgnored(prop.Type))) |
||||||
|
{ |
||||||
|
if (prop.IsInRefTypeAndBackedByValueClassField()) |
||||||
|
{ |
||||||
|
prop.Field.Visit(this); |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
prop.Visit(this); |
||||||
|
} |
||||||
|
Unindent(); |
||||||
|
} |
||||||
|
|
||||||
|
public virtual void GenerateIndexer(Property property) |
||||||
|
{ |
||||||
|
throw new System.NotImplementedException(); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitProperty(Property property) |
||||||
|
{ |
||||||
|
GenerateDeclarationCommon(property); |
||||||
|
|
||||||
|
return base.VisitProperty(property); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitMethodDecl(Method method) |
||||||
|
{ |
||||||
|
if (ASTUtils.CheckIgnoreMethod(method) || FunctionIgnored(method)) |
||||||
|
return false; |
||||||
|
|
||||||
|
PushBlock(BlockKind.Method, method); |
||||||
|
GenerateDeclarationCommon(method); |
||||||
|
|
||||||
|
GenerateMethodSpecifier(method, method.Namespace as Class); |
||||||
|
WriteLine(";"); |
||||||
|
|
||||||
|
PopBlock(NewLineKind.BeforeNextBlock); |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitTypedefNameDecl(TypedefNameDecl typedef) |
||||||
|
{ |
||||||
|
if (!typedef.IsGenerated) |
||||||
|
return false; |
||||||
|
|
||||||
|
var functionType = typedef.Type as FunctionType; |
||||||
|
if (functionType != null || typedef.Type.IsPointerTo(out functionType)) |
||||||
|
{ |
||||||
|
PushBlock(BlockKind.Typedef, typedef); |
||||||
|
GenerateDeclarationCommon(typedef); |
||||||
|
|
||||||
|
var @delegate = string.Format(CTypePrinter.VisitDelegate(functionType), typedef.Name); |
||||||
|
WriteLine($"{@delegate};"); |
||||||
|
|
||||||
|
PopBlock(NewLineKind.BeforeNextBlock); |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitFunctionDecl(Function function) |
||||||
|
{ |
||||||
|
if (!function.IsGenerated || FunctionIgnored(function)) |
||||||
|
return false; |
||||||
|
|
||||||
|
PushBlock(BlockKind.Function, function); |
||||||
|
|
||||||
|
GenerateDeclarationCommon(function); |
||||||
|
|
||||||
|
var retType = function.ReturnType.Visit(CTypePrinter); |
||||||
|
Write($"{retType} {function.Name}("); |
||||||
|
|
||||||
|
GenerateMethodParameters(function); |
||||||
|
WriteLine(");"); |
||||||
|
|
||||||
|
PopBlock(); |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public static bool FunctionIgnored(Function function) |
||||||
|
{ |
||||||
|
return TypeIgnored(function.ReturnType.Type) || |
||||||
|
function.Parameters.Any(param => TypeIgnored(param.Type)); |
||||||
|
} |
||||||
|
|
||||||
|
public static bool TypeIgnored(CppSharp.AST.Type type) |
||||||
|
{ |
||||||
|
var desugared = type.Desugar(); |
||||||
|
var finalType = (desugared.GetFinalPointee() ?? desugared).Desugar(); |
||||||
|
Class @class; |
||||||
|
return finalType.TryGetClass(out @class) && @class.IsIncomplete; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,682 @@ |
|||||||
|
using System; |
||||||
|
using CppSharp.AST; |
||||||
|
using CppSharp.AST.Extensions; |
||||||
|
using CppSharp.Generators.C; |
||||||
|
using CppSharp.Generators.CLI; |
||||||
|
using CppSharp.Types; |
||||||
|
using Delegate = CppSharp.AST.Delegate; |
||||||
|
using Type = CppSharp.AST.Type; |
||||||
|
|
||||||
|
namespace CppSharp.Generators.Cpp |
||||||
|
{ |
||||||
|
public class CppMarshalNativeToManagedPrinter : MarshalPrinter<MarshalContext> |
||||||
|
{ |
||||||
|
public CppMarshalNativeToManagedPrinter(MarshalContext marshalContext) |
||||||
|
: base(marshalContext) |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
public string MemoryAllocOperator => |
||||||
|
(Context.Context.Options.GeneratorKind == GeneratorKind.CLI) ? |
||||||
|
"gcnew" : "new"; |
||||||
|
|
||||||
|
public override bool VisitType(Type type, TypeQualifiers quals) |
||||||
|
{ |
||||||
|
TypeMap typeMap; |
||||||
|
if (Context.Context.TypeMaps.FindTypeMap(type, out typeMap) && typeMap.DoesMarshalling) |
||||||
|
{ |
||||||
|
typeMap.CppMarshalToManaged(Context); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitArrayType(ArrayType array, TypeQualifiers quals) |
||||||
|
{ |
||||||
|
switch (array.SizeType) |
||||||
|
{ |
||||||
|
case ArrayType.ArraySize.Constant: |
||||||
|
case ArrayType.ArraySize.Incomplete: |
||||||
|
case ArrayType.ArraySize.Variable: |
||||||
|
Context.Return.Write("nullptr"); |
||||||
|
break; |
||||||
|
default: |
||||||
|
throw new System.NotImplementedException(); |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitFunctionType(FunctionType function, TypeQualifiers quals) |
||||||
|
{ |
||||||
|
Context.Return.Write(Context.ReturnVarName); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitPointerType(PointerType pointer, TypeQualifiers quals) |
||||||
|
{ |
||||||
|
if (!VisitType(pointer, quals)) |
||||||
|
return false; |
||||||
|
|
||||||
|
var pointee = pointer.Pointee.Desugar(); |
||||||
|
|
||||||
|
PrimitiveType primitive; |
||||||
|
var param = Context.Parameter; |
||||||
|
if (param != null && (param.IsOut || param.IsInOut) && |
||||||
|
pointee.IsPrimitiveType(out primitive)) |
||||||
|
{ |
||||||
|
Context.Return.Write(Context.ReturnVarName); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
if (pointee.IsPrimitiveType(out primitive)) |
||||||
|
{ |
||||||
|
var returnVarName = Context.ReturnVarName; |
||||||
|
|
||||||
|
if (pointer.GetFinalQualifiedPointee().Qualifiers.IsConst != |
||||||
|
Context.ReturnType.Qualifiers.IsConst) |
||||||
|
{ |
||||||
|
var nativeTypePrinter = new CppTypePrinter { PrintTypeQualifiers = false }; |
||||||
|
var returnType = Context.ReturnType.Type.Desugar(); |
||||||
|
var constlessPointer = new PointerType() |
||||||
|
{ |
||||||
|
IsDependent = pointer.IsDependent, |
||||||
|
Modifier = pointer.Modifier, |
||||||
|
QualifiedPointee = new QualifiedType(returnType.GetPointee()) |
||||||
|
}; |
||||||
|
var nativeConstlessTypeName = constlessPointer.Visit(nativeTypePrinter, new TypeQualifiers()); |
||||||
|
returnVarName = string.Format("const_cast<{0}>({1})", |
||||||
|
nativeConstlessTypeName, Context.ReturnVarName); |
||||||
|
} |
||||||
|
|
||||||
|
if (pointer.Pointee is TypedefType) |
||||||
|
{ |
||||||
|
var desugaredPointer = new PointerType() |
||||||
|
{ |
||||||
|
IsDependent = pointer.IsDependent, |
||||||
|
Modifier = pointer.Modifier, |
||||||
|
QualifiedPointee = new QualifiedType(pointee) |
||||||
|
}; |
||||||
|
var nativeTypePrinter = new CppTypePrinter(); |
||||||
|
var nativeTypeName = desugaredPointer.Visit(nativeTypePrinter, quals); |
||||||
|
Context.Return.Write("reinterpret_cast<{0}>({1})", nativeTypeName, |
||||||
|
returnVarName); |
||||||
|
} |
||||||
|
else |
||||||
|
Context.Return.Write(returnVarName); |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
TypeMap typeMap = null; |
||||||
|
Context.Context.TypeMaps.FindTypeMap(pointee, out typeMap); |
||||||
|
|
||||||
|
Class @class; |
||||||
|
if (pointee.TryGetClass(out @class) && typeMap == null) |
||||||
|
{ |
||||||
|
var instance = (pointer.IsReference) ? "&" + Context.ReturnVarName |
||||||
|
: Context.ReturnVarName; |
||||||
|
WriteClassInstance(@class, instance); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
return pointer.QualifiedPointee.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitMemberPointerType(MemberPointerType member, |
||||||
|
TypeQualifiers quals) |
||||||
|
{ |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
public override 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.Char: |
||||||
|
case PrimitiveType.Char16: |
||||||
|
case PrimitiveType.WideChar: |
||||||
|
case PrimitiveType.SChar: |
||||||
|
case PrimitiveType.UChar: |
||||||
|
case PrimitiveType.Short: |
||||||
|
case PrimitiveType.UShort: |
||||||
|
case PrimitiveType.Int: |
||||||
|
case PrimitiveType.UInt: |
||||||
|
case PrimitiveType.Long: |
||||||
|
case PrimitiveType.ULong: |
||||||
|
case PrimitiveType.LongLong: |
||||||
|
case PrimitiveType.ULongLong: |
||||||
|
case PrimitiveType.Float: |
||||||
|
case PrimitiveType.Double: |
||||||
|
case PrimitiveType.LongDouble: |
||||||
|
case PrimitiveType.Null: |
||||||
|
Context.Return.Write(Context.ReturnVarName); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
throw new NotSupportedException(); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitTypedefType(TypedefType typedef, TypeQualifiers quals) |
||||||
|
{ |
||||||
|
var decl = typedef.Declaration; |
||||||
|
|
||||||
|
TypeMap typeMap; |
||||||
|
if (Context.Context.TypeMaps.FindTypeMap(decl.Type, out typeMap) && |
||||||
|
typeMap.DoesMarshalling) |
||||||
|
{ |
||||||
|
typeMap.Type = typedef; |
||||||
|
typeMap.CppMarshalToManaged(Context); |
||||||
|
return typeMap.IsValueType; |
||||||
|
} |
||||||
|
|
||||||
|
FunctionType function; |
||||||
|
if (decl.Type.IsPointerTo(out function)) |
||||||
|
{ |
||||||
|
throw new System.NotImplementedException(); |
||||||
|
} |
||||||
|
|
||||||
|
return decl.Type.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitTemplateSpecializationType(TemplateSpecializationType template, |
||||||
|
TypeQualifiers quals) |
||||||
|
{ |
||||||
|
TypeMap typeMap; |
||||||
|
if (Context.Context.TypeMaps.FindTypeMap(template, out typeMap) && typeMap.DoesMarshalling) |
||||||
|
{ |
||||||
|
typeMap.Type = template; |
||||||
|
typeMap.CppMarshalToManaged(Context); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
return template.Template.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitTemplateParameterType(TemplateParameterType param, TypeQualifiers quals) |
||||||
|
{ |
||||||
|
throw new NotImplementedException(); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitPrimitiveType(PrimitiveType type, TypeQualifiers quals) |
||||||
|
{ |
||||||
|
throw new NotImplementedException(); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitDeclaration(Declaration decl, TypeQualifiers quals) |
||||||
|
{ |
||||||
|
throw new NotImplementedException(); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitClassDecl(Class @class) |
||||||
|
{ |
||||||
|
if (@class.CompleteDeclaration != null) |
||||||
|
return VisitClassDecl(@class.CompleteDeclaration as Class); |
||||||
|
|
||||||
|
var instance = string.Empty; |
||||||
|
|
||||||
|
if (Context.Context.Options.GeneratorKind == GeneratorKind.CLI) |
||||||
|
{ |
||||||
|
if (!Context.ReturnType.Type.IsPointer()) |
||||||
|
instance += "&"; |
||||||
|
} |
||||||
|
|
||||||
|
instance += Context.ReturnVarName; |
||||||
|
var needsCopy = Context.MarshalKind != MarshalKind.NativeField; |
||||||
|
|
||||||
|
if (@class.IsRefType && needsCopy) |
||||||
|
{ |
||||||
|
var name = Generator.GeneratedIdentifier(Context.ReturnVarName); |
||||||
|
Context.Before.WriteLine($"auto {name} = {MemoryAllocOperator} ::{0}({1});", |
||||||
|
@class.QualifiedOriginalName, Context.ReturnVarName); |
||||||
|
instance = name; |
||||||
|
} |
||||||
|
|
||||||
|
WriteClassInstance(@class, instance); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public string QualifiedIdentifier(Declaration decl) |
||||||
|
{ |
||||||
|
if (!string.IsNullOrEmpty(decl.TranslationUnit.Module.OutputNamespace)) |
||||||
|
return $"{decl.TranslationUnit.Module.OutputNamespace}::{decl.QualifiedName}"; |
||||||
|
|
||||||
|
return decl.QualifiedName; |
||||||
|
} |
||||||
|
|
||||||
|
public void WriteClassInstance(Class @class, string instance) |
||||||
|
{ |
||||||
|
if (!Context.ReturnType.Type.IsPointer()) |
||||||
|
{ |
||||||
|
Context.Return.Write($"{instance}"); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
if (@class.IsRefType) |
||||||
|
Context.Return.Write($"({instance} == nullptr) ? nullptr : {MemoryAllocOperator} "); |
||||||
|
|
||||||
|
Context.Return.Write($"{QualifiedIdentifier(@class)}("); |
||||||
|
Context.Return.Write($"(::{@class.QualifiedOriginalName}*)"); |
||||||
|
Context.Return.Write($"{instance})"); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitFieldDecl(Field field) |
||||||
|
{ |
||||||
|
return field.Type.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitFunctionDecl(Function function) |
||||||
|
{ |
||||||
|
throw new NotImplementedException(); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitMethodDecl(Method method) |
||||||
|
{ |
||||||
|
throw new NotImplementedException(); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitParameterDecl(Parameter parameter) |
||||||
|
{ |
||||||
|
Context.Parameter = parameter; |
||||||
|
var ret = parameter.Type.Visit(this, parameter.QualifiedType.Qualifiers); |
||||||
|
Context.Parameter = null; |
||||||
|
|
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitTypedefDecl(TypedefDecl typedef) |
||||||
|
{ |
||||||
|
throw new NotImplementedException(); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitEnumDecl(Enumeration @enum) |
||||||
|
{ |
||||||
|
var typePrinter = new CppTypePrinter(); |
||||||
|
var typeName = typePrinter.VisitDeclaration(@enum); |
||||||
|
Context.Return.Write($"({typeName}){Context.ReturnVarName}"); |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitVariableDecl(Variable variable) |
||||||
|
{ |
||||||
|
return variable.Type.Visit(this, variable.QualifiedType.Qualifiers); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitClassTemplateDecl(ClassTemplate template) |
||||||
|
{ |
||||||
|
return template.TemplatedClass.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitFunctionTemplateDecl(FunctionTemplate template) |
||||||
|
{ |
||||||
|
return template.TemplatedFunction.Visit(this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public class CppMarshalManagedToNativePrinter : MarshalPrinter<MarshalContext> |
||||||
|
{ |
||||||
|
public readonly TextGenerator VarPrefix; |
||||||
|
public readonly TextGenerator ArgumentPrefix; |
||||||
|
|
||||||
|
public CppMarshalManagedToNativePrinter(MarshalContext ctx) |
||||||
|
: base(ctx) |
||||||
|
{ |
||||||
|
VarPrefix = new TextGenerator(); |
||||||
|
ArgumentPrefix = new TextGenerator(); |
||||||
|
|
||||||
|
Context.MarshalToNative = this; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitType(Type type, TypeQualifiers quals) |
||||||
|
{ |
||||||
|
TypeMap typeMap; |
||||||
|
if (Context.Context.TypeMaps.FindTypeMap(type, out typeMap) && typeMap.DoesMarshalling) |
||||||
|
{ |
||||||
|
typeMap.CppMarshalToNative(Context); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitTagType(TagType tag, TypeQualifiers quals) |
||||||
|
{ |
||||||
|
if (!VisitType(tag, quals)) |
||||||
|
return false; |
||||||
|
|
||||||
|
return tag.Declaration.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitArrayType(ArrayType array, TypeQualifiers quals) |
||||||
|
{ |
||||||
|
if (!VisitType(array, quals)) |
||||||
|
return false; |
||||||
|
|
||||||
|
switch (array.SizeType) |
||||||
|
{ |
||||||
|
default: |
||||||
|
Context.Return.Write("nullptr"); |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitFunctionType(FunctionType function, TypeQualifiers quals) |
||||||
|
{ |
||||||
|
var returnType = function.ReturnType; |
||||||
|
return returnType.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public bool VisitDelegateType(string type) |
||||||
|
{ |
||||||
|
Context.Return.Write(Context.Parameter.Name); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitPointerType(PointerType pointer, TypeQualifiers quals) |
||||||
|
{ |
||||||
|
if (!VisitType(pointer, quals)) |
||||||
|
return false; |
||||||
|
|
||||||
|
var pointee = pointer.Pointee.Desugar(); |
||||||
|
|
||||||
|
if (pointee is FunctionType) |
||||||
|
{ |
||||||
|
var cppTypePrinter = new CppTypePrinter(); |
||||||
|
var cppTypeName = pointer.Visit(cppTypePrinter, quals); |
||||||
|
|
||||||
|
return VisitDelegateType(cppTypeName); |
||||||
|
} |
||||||
|
|
||||||
|
Enumeration @enum; |
||||||
|
if (pointee.TryGetEnum(out @enum)) |
||||||
|
{ |
||||||
|
var isRef = Context.Parameter.Usage == ParameterUsage.Out || |
||||||
|
Context.Parameter.Usage == ParameterUsage.InOut; |
||||||
|
|
||||||
|
ArgumentPrefix.Write("&"); |
||||||
|
Context.Return.Write($"(::{@enum.QualifiedOriginalName}){0}{Context.Parameter.Name}", |
||||||
|
isRef ? string.Empty : "*"); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
Class @class; |
||||||
|
if (pointee.TryGetClass(out @class) && @class.IsValueType) |
||||||
|
{ |
||||||
|
if (Context.Function == null) |
||||||
|
Context.Return.Write("&"); |
||||||
|
return pointer.QualifiedPointee.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
var finalPointee = pointer.GetFinalPointee(); |
||||||
|
if (finalPointee.IsPrimitiveType()) |
||||||
|
{ |
||||||
|
var cppTypePrinter = new CppTypePrinter(); |
||||||
|
var cppTypeName = pointer.Visit(cppTypePrinter, quals); |
||||||
|
|
||||||
|
Context.Return.Write($"({cppTypeName})"); |
||||||
|
Context.Return.Write(Context.Parameter.Name); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
return pointer.QualifiedPointee.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitMemberPointerType(MemberPointerType member, |
||||||
|
TypeQualifiers quals) |
||||||
|
{ |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
public override 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.Char: |
||||||
|
case PrimitiveType.UChar: |
||||||
|
case PrimitiveType.Short: |
||||||
|
case PrimitiveType.UShort: |
||||||
|
case PrimitiveType.Int: |
||||||
|
case PrimitiveType.UInt: |
||||||
|
case PrimitiveType.Long: |
||||||
|
case PrimitiveType.ULong: |
||||||
|
case PrimitiveType.LongLong: |
||||||
|
case PrimitiveType.ULongLong: |
||||||
|
case PrimitiveType.Float: |
||||||
|
case PrimitiveType.Double: |
||||||
|
Context.Return.Write(Context.Parameter.Name); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitTypedefType(TypedefType typedef, TypeQualifiers quals) |
||||||
|
{ |
||||||
|
var decl = typedef.Declaration; |
||||||
|
|
||||||
|
TypeMap typeMap; |
||||||
|
if (Context.Context.TypeMaps.FindTypeMap(decl.Type, out typeMap) && |
||||||
|
typeMap.DoesMarshalling) |
||||||
|
{ |
||||||
|
typeMap.CppMarshalToNative(Context); |
||||||
|
return typeMap.IsValueType; |
||||||
|
} |
||||||
|
|
||||||
|
FunctionType func; |
||||||
|
if (decl.Type.IsPointerTo(out func)) |
||||||
|
{ |
||||||
|
// Use the original typedef name if available, otherwise just use the function pointer type
|
||||||
|
string cppTypeName; |
||||||
|
if (!decl.IsSynthetized) |
||||||
|
cppTypeName = "::" + typedef.Declaration.QualifiedOriginalName; |
||||||
|
else |
||||||
|
{ |
||||||
|
var cppTypePrinter = new CppTypePrinter(); |
||||||
|
cppTypeName = decl.Type.Visit(cppTypePrinter, quals); |
||||||
|
} |
||||||
|
|
||||||
|
VisitDelegateType(cppTypeName); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
PrimitiveType primitive; |
||||||
|
if (decl.Type.IsPrimitiveType(out primitive)) |
||||||
|
{ |
||||||
|
Context.Return.Write($"(::{typedef.Declaration.QualifiedOriginalName})"); |
||||||
|
} |
||||||
|
|
||||||
|
return decl.Type.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitTemplateSpecializationType(TemplateSpecializationType template, |
||||||
|
TypeQualifiers quals) |
||||||
|
{ |
||||||
|
TypeMap typeMap; |
||||||
|
if (Context.Context.TypeMaps.FindTypeMap(template, out typeMap) && typeMap.DoesMarshalling) |
||||||
|
{ |
||||||
|
typeMap.Type = template; |
||||||
|
typeMap.CppMarshalToNative(Context); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
return template.Template.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitTemplateParameterType(TemplateParameterType param, TypeQualifiers quals) |
||||||
|
{ |
||||||
|
Context.Return.Write(param.Parameter.Name); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitPrimitiveType(PrimitiveType type, TypeQualifiers quals) |
||||||
|
{ |
||||||
|
throw new NotImplementedException(); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitDeclaration(Declaration decl, TypeQualifiers quals) |
||||||
|
{ |
||||||
|
throw new NotImplementedException(); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitClassDecl(Class @class) |
||||||
|
{ |
||||||
|
if (@class.CompleteDeclaration != null) |
||||||
|
return VisitClassDecl(@class.CompleteDeclaration as Class); |
||||||
|
|
||||||
|
if (@class.IsValueType) |
||||||
|
{ |
||||||
|
MarshalValueClass(@class); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
MarshalRefClass(@class); |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
private void MarshalRefClass(Class @class) |
||||||
|
{ |
||||||
|
var type = Context.Parameter.Type.Desugar(); |
||||||
|
TypeMap typeMap; |
||||||
|
if (Context.Context.TypeMaps.FindTypeMap(type, out typeMap) && |
||||||
|
typeMap.DoesMarshalling) |
||||||
|
{ |
||||||
|
typeMap.CppMarshalToNative(Context); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
if (!type.SkipPointerRefs().IsPointer()) |
||||||
|
{ |
||||||
|
Context.Return.Write("*"); |
||||||
|
|
||||||
|
if (Context.Parameter.Type.IsReference()) |
||||||
|
VarPrefix.Write("&"); |
||||||
|
} |
||||||
|
|
||||||
|
var method = Context.Function as Method; |
||||||
|
if (method != null |
||||||
|
&& method.Conversion == MethodConversionKind.FunctionToInstanceMethod |
||||||
|
&& Context.ParameterIndex == 0) |
||||||
|
{ |
||||||
|
Context.Return.Write($"(::{@class.QualifiedOriginalName}*)"); |
||||||
|
Context.Return.Write(Helpers.InstanceIdentifier); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
var paramType = Context.Parameter.Type.Desugar(); |
||||||
|
var deref = paramType.SkipPointerRefs().IsPointer() ? "->" : "."; |
||||||
|
Context.Return.Write($"(::{@class.QualifiedOriginalName}*)"); |
||||||
|
Context.Return.Write($"{Context.Parameter.Name}{deref}{Helpers.InstanceIdentifier}"); |
||||||
|
} |
||||||
|
|
||||||
|
private void MarshalValueClass(Class @class) |
||||||
|
{ |
||||||
|
throw new System.NotImplementedException(); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitFieldDecl(Field field) |
||||||
|
{ |
||||||
|
Context.Parameter = new Parameter |
||||||
|
{ |
||||||
|
Name = Context.ArgName, |
||||||
|
QualifiedType = field.QualifiedType |
||||||
|
}; |
||||||
|
|
||||||
|
return field.Type.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitProperty(Property property) |
||||||
|
{ |
||||||
|
Context.Parameter = new Parameter |
||||||
|
{ |
||||||
|
Name = Context.ArgName, |
||||||
|
QualifiedType = property.QualifiedType |
||||||
|
}; |
||||||
|
|
||||||
|
return base.VisitProperty(property); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitFunctionDecl(Function function) |
||||||
|
{ |
||||||
|
throw new NotImplementedException(); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitMethodDecl(Method method) |
||||||
|
{ |
||||||
|
throw new NotImplementedException(); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitParameterDecl(Parameter parameter) |
||||||
|
{ |
||||||
|
return parameter.Type.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitTypedefDecl(TypedefDecl typedef) |
||||||
|
{ |
||||||
|
throw new NotImplementedException(); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitEnumDecl(Enumeration @enum) |
||||||
|
{ |
||||||
|
Context.Return.Write("(::{0}){1}", @enum.QualifiedOriginalName, |
||||||
|
Context.Parameter.Name); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitVariableDecl(Variable variable) |
||||||
|
{ |
||||||
|
throw new NotImplementedException(); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitClassTemplateDecl(ClassTemplate template) |
||||||
|
{ |
||||||
|
return template.TemplatedClass.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitFunctionTemplateDecl(FunctionTemplate template) |
||||||
|
{ |
||||||
|
return template.TemplatedFunction.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitMacroDefinition(MacroDefinition macro) |
||||||
|
{ |
||||||
|
throw new NotImplementedException(); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitNamespace(Namespace @namespace) |
||||||
|
{ |
||||||
|
throw new NotImplementedException(); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitEvent(Event @event) |
||||||
|
{ |
||||||
|
throw new NotImplementedException(); |
||||||
|
} |
||||||
|
|
||||||
|
public bool VisitDelegate(Delegate @delegate) |
||||||
|
{ |
||||||
|
throw new NotImplementedException(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,626 @@ |
|||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Globalization; |
||||||
|
using System.IO; |
||||||
|
using System.Linq; |
||||||
|
using CppSharp.AST; |
||||||
|
using CppSharp.AST.Extensions; |
||||||
|
using CppSharp.Generators.C; |
||||||
|
using CppSharp.Generators.CLI; |
||||||
|
|
||||||
|
namespace CppSharp.Generators.Cpp |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Generates C/C++ source files.
|
||||||
|
/// </summary>
|
||||||
|
public class CppSources : CCodeGenerator |
||||||
|
{ |
||||||
|
public CppSources(BindingContext context, IEnumerable<TranslationUnit> units) |
||||||
|
: base(context, units) |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
public override string FileExtension { get { return "cpp"; } } |
||||||
|
|
||||||
|
public override void Process() |
||||||
|
{ |
||||||
|
GenerateFilePreamble(CommentKind.BCPL); |
||||||
|
|
||||||
|
var file = Path.GetFileNameWithoutExtension(TranslationUnit.FileName) |
||||||
|
.Replace('\\', '/'); |
||||||
|
|
||||||
|
if (Context.Options.GenerateName != null) |
||||||
|
file = Context.Options.GenerateName(TranslationUnit); |
||||||
|
|
||||||
|
PushBlock(BlockKind.Includes); |
||||||
|
WriteLine("#include \"{0}.h\"", file); |
||||||
|
GenerateForwardReferenceHeaders(); |
||||||
|
|
||||||
|
NewLine(); |
||||||
|
PopBlock(); |
||||||
|
|
||||||
|
VisitDeclContext(TranslationUnit); |
||||||
|
|
||||||
|
PushBlock(BlockKind.Footer); |
||||||
|
PopBlock(); |
||||||
|
} |
||||||
|
|
||||||
|
public void GenerateForwardReferenceHeaders() |
||||||
|
{ |
||||||
|
PushBlock(BlockKind.IncludesForwardReferences); |
||||||
|
|
||||||
|
var typeReferenceCollector = new CLITypeReferenceCollector(Context.TypeMaps, Context.Options); |
||||||
|
typeReferenceCollector.Process(TranslationUnit, filterNamespaces: false); |
||||||
|
|
||||||
|
var includes = new SortedSet<string>(StringComparer.InvariantCulture); |
||||||
|
|
||||||
|
foreach (var typeRef in typeReferenceCollector.TypeReferences) |
||||||
|
{ |
||||||
|
if (typeRef.Include.File == TranslationUnit.FileName) |
||||||
|
continue; |
||||||
|
|
||||||
|
var include = typeRef.Include; |
||||||
|
if(!string.IsNullOrEmpty(include.File) && !include.InHeader) |
||||||
|
includes.Add(include.ToString()); |
||||||
|
} |
||||||
|
|
||||||
|
foreach (var include in includes) |
||||||
|
WriteLine(include); |
||||||
|
|
||||||
|
PopBlock(); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitDeclContext(DeclarationContext context) |
||||||
|
{ |
||||||
|
PushBlock(BlockKind.Namespace); |
||||||
|
foreach (var @class in context.Classes) |
||||||
|
{ |
||||||
|
if (!@class.IsGenerated || @class.IsDependent) |
||||||
|
continue; |
||||||
|
|
||||||
|
if (@class.IsOpaque || @class.IsIncomplete) |
||||||
|
continue; |
||||||
|
|
||||||
|
@class.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
// Generate all the function declarations for the module.
|
||||||
|
foreach (var function in context.Functions.Where(f => f.IsGenerated)) |
||||||
|
{ |
||||||
|
function.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
if (Options.GenerateFunctionTemplates) |
||||||
|
{ |
||||||
|
foreach (var template in context.Templates) |
||||||
|
{ |
||||||
|
if (!template.IsGenerated) continue; |
||||||
|
|
||||||
|
var functionTemplate = template as FunctionTemplate; |
||||||
|
if (functionTemplate == null) continue; |
||||||
|
|
||||||
|
if (!functionTemplate.IsGenerated) |
||||||
|
continue; |
||||||
|
|
||||||
|
GenerateFunctionTemplate(functionTemplate); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
foreach(var childNamespace in context.Namespaces) |
||||||
|
VisitDeclContext(childNamespace); |
||||||
|
|
||||||
|
PopBlock(); |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public void GenerateClass(Class @class) |
||||||
|
{ |
||||||
|
PushBlock(BlockKind.Class); |
||||||
|
|
||||||
|
VisitDeclContext(@class); |
||||||
|
|
||||||
|
GenerateClassConstructors(@class); |
||||||
|
GenerateClassMethods(@class); |
||||||
|
GenerateClassProperties(@class); |
||||||
|
|
||||||
|
foreach (var @event in @class.Events) |
||||||
|
{ |
||||||
|
if (!@event.IsGenerated) |
||||||
|
continue; |
||||||
|
|
||||||
|
@event.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
foreach (var variable in @class.Variables) |
||||||
|
{ |
||||||
|
if (!variable.IsGenerated) |
||||||
|
continue; |
||||||
|
|
||||||
|
if (variable.Access != AccessSpecifier.Public) |
||||||
|
continue; |
||||||
|
|
||||||
|
variable.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
PopBlock(); |
||||||
|
} |
||||||
|
|
||||||
|
public virtual void GenerateClassConstructors(Class @class) |
||||||
|
{ |
||||||
|
if (@class.IsStatic) |
||||||
|
return; |
||||||
|
|
||||||
|
// Output a default constructor that takes the native instance.
|
||||||
|
GenerateClassConstructor(@class); |
||||||
|
|
||||||
|
if (@class.IsRefType) |
||||||
|
{ |
||||||
|
var destructor = @class.Destructors |
||||||
|
.FirstOrDefault(d => d.Parameters.Count == 0 && d.Access == AccessSpecifier.Public); |
||||||
|
|
||||||
|
if (destructor != null) |
||||||
|
{ |
||||||
|
GenerateClassDestructor(@class); |
||||||
|
|
||||||
|
if (Options.GenerateFinalizers) |
||||||
|
GenerateClassFinalizer(@class); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public virtual void GenerateClassMethods(Class @class) |
||||||
|
{ |
||||||
|
foreach (var method in @class.Methods.Where(m => !m.IsOperator)) |
||||||
|
{ |
||||||
|
if (ASTUtils.CheckIgnoreMethod(method) || CppHeaders.FunctionIgnored(method)) |
||||||
|
continue; |
||||||
|
|
||||||
|
// Do not generate property getter/setter methods as they will be generated
|
||||||
|
// as part of properties generation.
|
||||||
|
var field = (method?.AssociatedDeclaration as Property)?.Field; |
||||||
|
if (field != null) |
||||||
|
continue; |
||||||
|
|
||||||
|
method.Visit(this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public virtual void GenerateClassProperties(Class @class) |
||||||
|
{ |
||||||
|
foreach (var property in @class.Properties) |
||||||
|
{ |
||||||
|
if (ASTUtils.CheckIgnoreProperty(property) || CppHeaders.TypeIgnored(property.Type)) |
||||||
|
continue; |
||||||
|
|
||||||
|
property.Visit(this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public virtual void GenerateClassDestructor(Class @class) |
||||||
|
{ |
||||||
|
PushBlock(BlockKind.Destructor); |
||||||
|
|
||||||
|
WriteLine($"{QualifiedIdentifier(@class)}::~{@class.Name}()"); |
||||||
|
WriteOpenBraceAndIndent(); |
||||||
|
UnindentAndWriteCloseBrace(); |
||||||
|
|
||||||
|
PopBlock(NewLineKind.BeforeNextBlock); |
||||||
|
} |
||||||
|
|
||||||
|
public virtual void GenerateClassFinalizer(Class @class) |
||||||
|
{ |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public virtual void GenerateFunctionTemplate(FunctionTemplate template) |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitProperty(Property property) |
||||||
|
{ |
||||||
|
PushBlock(BlockKind.Property, property); |
||||||
|
|
||||||
|
if (property.HasGetter) |
||||||
|
GeneratePropertyGetter(property.GetMethod); |
||||||
|
|
||||||
|
if (property.HasSetter) |
||||||
|
GeneratePropertySetter(property.SetMethod); |
||||||
|
|
||||||
|
PopBlock(); |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public override void GeneratePropertyGetter(Method method) |
||||||
|
{ |
||||||
|
PushBlock(BlockKind.Method, method); |
||||||
|
|
||||||
|
var property = method.AssociatedDeclaration as Property; |
||||||
|
GeneratePropertyAccessorSpecifier(method); |
||||||
|
NewLine(); |
||||||
|
|
||||||
|
WriteOpenBraceAndIndent(); |
||||||
|
|
||||||
|
GenerateFunctionCall(method); |
||||||
|
|
||||||
|
UnindentAndWriteCloseBrace(); |
||||||
|
NewLine(); |
||||||
|
|
||||||
|
PopBlock(NewLineKind.BeforeNextBlock); |
||||||
|
} |
||||||
|
|
||||||
|
public override void GeneratePropertySetter(Method method) |
||||||
|
{ |
||||||
|
PushBlock(BlockKind.Method, method); |
||||||
|
|
||||||
|
var property = method.AssociatedDeclaration as Property; |
||||||
|
GeneratePropertyAccessorSpecifier(method); |
||||||
|
NewLine(); |
||||||
|
|
||||||
|
WriteOpenBraceAndIndent(); |
||||||
|
|
||||||
|
GenerateFunctionCall(method); |
||||||
|
|
||||||
|
UnindentAndWriteCloseBrace(); |
||||||
|
NewLine(); |
||||||
|
|
||||||
|
PopBlock(NewLineKind.BeforeNextBlock); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitEvent(Event @event) |
||||||
|
{ |
||||||
|
GenerateDeclarationCommon(@event); |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitVariableDecl(Variable variable) |
||||||
|
{ |
||||||
|
GenerateDeclarationCommon(variable); |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public virtual string ClassCtorInstanceParamIdentifier => "instance"; |
||||||
|
|
||||||
|
public virtual void GenerateClassConstructor(Class @class) |
||||||
|
{ |
||||||
|
Write($"{QualifiedIdentifier(@class)}::{@class.Name}("); |
||||||
|
|
||||||
|
var nativeType = $"::{@class.QualifiedOriginalName}*"; |
||||||
|
WriteLine($"{nativeType} {ClassCtorInstanceParamIdentifier})"); |
||||||
|
|
||||||
|
WriteOpenBraceAndIndent(); |
||||||
|
|
||||||
|
UnindentAndWriteCloseBrace(); |
||||||
|
NewLine(); |
||||||
|
} |
||||||
|
|
||||||
|
private bool GenerateClassConstructorBase(Class @class, Method method = null) |
||||||
|
{ |
||||||
|
var hasBase = @class.HasBase && @class.Bases[0].IsClass && @class.Bases[0].Class.IsGenerated; |
||||||
|
if (!hasBase) |
||||||
|
return false; |
||||||
|
|
||||||
|
if (!@class.IsValueType) |
||||||
|
{ |
||||||
|
Indent(); |
||||||
|
|
||||||
|
var baseClass = @class.Bases[0].Class; |
||||||
|
Write(": {0}(", QualifiedIdentifier(baseClass)); |
||||||
|
|
||||||
|
// We cast the value to the base clas type since otherwise there
|
||||||
|
// could be ambiguous call to overloaded constructors.
|
||||||
|
var cppTypePrinter = new CppTypePrinter(); |
||||||
|
var nativeTypeName = baseClass.Visit(cppTypePrinter); |
||||||
|
Write("({0}*)", nativeTypeName); |
||||||
|
|
||||||
|
WriteLine("{0})", method != null ? "nullptr" : ClassCtorInstanceParamIdentifier); |
||||||
|
|
||||||
|
Unindent(); |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public override string GetMethodIdentifier(Function function, |
||||||
|
TypePrinterContextKind context = TypePrinterContextKind.Managed) |
||||||
|
{ |
||||||
|
var method = function as Method; |
||||||
|
if (method != null) |
||||||
|
{ |
||||||
|
var @class = method.Namespace as Class; |
||||||
|
return $"{QualifiedIdentifier(@class)}::{base.GetMethodIdentifier(method, context)}"; |
||||||
|
} |
||||||
|
|
||||||
|
return base.GetMethodIdentifier(function); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitMethodDecl(Method method) |
||||||
|
{ |
||||||
|
if (!method.IsGenerated || CppHeaders.FunctionIgnored(method)) |
||||||
|
return false; |
||||||
|
|
||||||
|
PushBlock(BlockKind.Method, method); |
||||||
|
|
||||||
|
GenerateMethodSpecifier(method, method.Namespace as Class); |
||||||
|
NewLine(); |
||||||
|
|
||||||
|
var @class = method.Namespace as Class; |
||||||
|
if (method.IsConstructor) |
||||||
|
GenerateClassConstructorBase(@class, method); |
||||||
|
|
||||||
|
WriteOpenBraceAndIndent(); |
||||||
|
|
||||||
|
PushBlock(BlockKind.MethodBody, method); |
||||||
|
|
||||||
|
if (method.IsConstructor && @class.IsRefType) |
||||||
|
WriteLine($"{Helpers.OwnsNativeInstanceIdentifier} = true;"); |
||||||
|
|
||||||
|
if (method.IsProxy) |
||||||
|
goto SkipImpl; |
||||||
|
|
||||||
|
if (@class.IsRefType) |
||||||
|
{ |
||||||
|
if (method.IsConstructor && !@class.IsAbstract) |
||||||
|
{ |
||||||
|
var @params = GenerateFunctionParamsMarshal(method.Parameters, method); |
||||||
|
Write($"{Helpers.InstanceIdentifier} = new ::{method.Namespace.QualifiedOriginalName}("); |
||||||
|
GenerateFunctionParams(@params); |
||||||
|
WriteLine(");"); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
GenerateFunctionCall(method); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
SkipImpl: |
||||||
|
|
||||||
|
PopBlock(); |
||||||
|
|
||||||
|
UnindentAndWriteCloseBrace(); |
||||||
|
|
||||||
|
PopBlock(NewLineKind.Always); |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public override bool VisitFunctionDecl(Function function) |
||||||
|
{ |
||||||
|
if (!function.IsGenerated || CppHeaders.FunctionIgnored(function)) |
||||||
|
return false; |
||||||
|
|
||||||
|
PushBlock(BlockKind.Function, function); |
||||||
|
|
||||||
|
GenerateDeclarationCommon(function); |
||||||
|
|
||||||
|
var returnType = function.ReturnType.Visit(CTypePrinter); |
||||||
|
|
||||||
|
var name = function.Visit(CTypePrinter); |
||||||
|
Write($"{returnType} {name}("); |
||||||
|
|
||||||
|
for (var i = 0; i < function.Parameters.Count; ++i) |
||||||
|
{ |
||||||
|
var param = function.Parameters[i]; |
||||||
|
Write($"{CTypePrinter.VisitParameter(param)}"); |
||||||
|
if (i < function.Parameters.Count - 1) |
||||||
|
Write(", "); |
||||||
|
} |
||||||
|
|
||||||
|
WriteLine(")"); |
||||||
|
WriteOpenBraceAndIndent(); |
||||||
|
|
||||||
|
GenerateFunctionCall(function); |
||||||
|
|
||||||
|
UnindentAndWriteCloseBrace(); |
||||||
|
|
||||||
|
PopBlock(NewLineKind.BeforeNextBlock); |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public void GenerateFunctionCall(Function function) |
||||||
|
{ |
||||||
|
var @params = GenerateFunctionParamsMarshal(function.Parameters, function); |
||||||
|
|
||||||
|
var needsReturn = !function.ReturnType.Type.IsPrimitiveType(PrimitiveType.Void); |
||||||
|
if (needsReturn) |
||||||
|
{ |
||||||
|
CTypePrinter.PushContext(TypePrinterContextKind.Native); |
||||||
|
var returnType = function.ReturnType.Visit(CTypePrinter); |
||||||
|
CTypePrinter.PopContext(); |
||||||
|
|
||||||
|
Write($"{returnType} {Helpers.ReturnIdentifier} = "); |
||||||
|
} |
||||||
|
|
||||||
|
var method = function as Method; |
||||||
|
var field = (method?.AssociatedDeclaration as Property)?.Field; |
||||||
|
var @class = function.Namespace as Class; |
||||||
|
|
||||||
|
if (field != null) |
||||||
|
{ |
||||||
|
Write($"((::{@class.QualifiedOriginalName}*){Helpers.InstanceIdentifier})->"); |
||||||
|
WriteLine ($"{field.OriginalName};"); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
if (IsNativeFunctionOrStaticMethod(function)) |
||||||
|
{ |
||||||
|
Write($"::{function.QualifiedOriginalName}("); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
if (IsNativeMethod(function)) |
||||||
|
Write($"((::{@class.QualifiedOriginalName}*){Helpers.InstanceIdentifier})->"); |
||||||
|
|
||||||
|
Write($"{base.GetMethodIdentifier(function, TypePrinterContextKind.Native)}("); |
||||||
|
} |
||||||
|
|
||||||
|
GenerateFunctionParams(@params); |
||||||
|
WriteLine(");"); |
||||||
|
} |
||||||
|
|
||||||
|
foreach(var paramInfo in @params) |
||||||
|
{ |
||||||
|
var param = paramInfo.Param; |
||||||
|
if(param.Usage != ParameterUsage.Out && param.Usage != ParameterUsage.InOut) |
||||||
|
continue; |
||||||
|
|
||||||
|
if (param.Type.IsPointer() && !param.Type.GetFinalPointee().IsPrimitiveType()) |
||||||
|
param.QualifiedType = new QualifiedType(param.Type.GetFinalPointee()); |
||||||
|
|
||||||
|
var nativeVarName = paramInfo.Name; |
||||||
|
|
||||||
|
var ctx = new MarshalContext(Context, CurrentIndentation) |
||||||
|
{ |
||||||
|
ArgName = nativeVarName, |
||||||
|
ReturnVarName = nativeVarName, |
||||||
|
ReturnType = param.QualifiedType |
||||||
|
}; |
||||||
|
|
||||||
|
var marshal = new CppMarshalNativeToManagedPrinter(ctx); |
||||||
|
param.Visit(marshal); |
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(marshal.Context.Before)) |
||||||
|
Write(marshal.Context.Before); |
||||||
|
|
||||||
|
WriteLine($"{param.Name} = {marshal.Context.Return};"); |
||||||
|
} |
||||||
|
|
||||||
|
if (needsReturn) |
||||||
|
{ |
||||||
|
var retTypeName = function.ReturnType.Visit(CTypePrinter).ToString(); |
||||||
|
|
||||||
|
var ctx = new MarshalContext(Context, CurrentIndentation) |
||||||
|
{ |
||||||
|
ArgName = Helpers.ReturnIdentifier, |
||||||
|
ReturnVarName = Helpers.ReturnIdentifier, |
||||||
|
ReturnType = function.ReturnType |
||||||
|
}; |
||||||
|
|
||||||
|
var marshal = new CppMarshalNativeToManagedPrinter(ctx); |
||||||
|
function.ReturnType.Visit(marshal); |
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(marshal.Context.Before)) |
||||||
|
Write(marshal.Context.Before); |
||||||
|
|
||||||
|
WriteLine($"return {marshal.Context.Return};"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static bool IsNativeMethod(Function function) |
||||||
|
{ |
||||||
|
var method = function as Method; |
||||||
|
if (method == null) |
||||||
|
return false; |
||||||
|
|
||||||
|
return method.Conversion == MethodConversionKind.None; |
||||||
|
} |
||||||
|
|
||||||
|
public bool IsNativeFunctionOrStaticMethod(Function function) |
||||||
|
{ |
||||||
|
var method = function as Method; |
||||||
|
if (method == null) |
||||||
|
return true; |
||||||
|
|
||||||
|
if (!IsCLIGenerator && method.IsOperator) |
||||||
|
return false; |
||||||
|
|
||||||
|
if (method.IsOperator && Operators.IsBuiltinOperator(method.OperatorKind)) |
||||||
|
return true; |
||||||
|
|
||||||
|
return method.IsStatic || method.Conversion != MethodConversionKind.None; |
||||||
|
} |
||||||
|
|
||||||
|
public struct ParamMarshal |
||||||
|
{ |
||||||
|
public string Name; |
||||||
|
public string Prefix; |
||||||
|
|
||||||
|
public Parameter Param; |
||||||
|
} |
||||||
|
|
||||||
|
public List<ParamMarshal> GenerateFunctionParamsMarshal(IEnumerable<Parameter> @params, |
||||||
|
Function function = null) |
||||||
|
{ |
||||||
|
var marshals = new List<ParamMarshal>(); |
||||||
|
|
||||||
|
var paramIndex = 0; |
||||||
|
foreach (var param in @params) |
||||||
|
{ |
||||||
|
marshals.Add(GenerateFunctionParamMarshal(param, paramIndex, function)); |
||||||
|
paramIndex++; |
||||||
|
} |
||||||
|
|
||||||
|
return marshals; |
||||||
|
} |
||||||
|
|
||||||
|
private ParamMarshal GenerateFunctionParamMarshal(Parameter param, int paramIndex, |
||||||
|
Function function = null) |
||||||
|
{ |
||||||
|
var paramMarshal = new ParamMarshal { Name = param.Name, Param = param }; |
||||||
|
|
||||||
|
if (param.Type is BuiltinType) |
||||||
|
return paramMarshal; |
||||||
|
|
||||||
|
var argName = Generator.GeneratedIdentifier("arg") + paramIndex.ToString(CultureInfo.InvariantCulture); |
||||||
|
|
||||||
|
Parameter effectiveParam = param; |
||||||
|
var isRef = param.IsOut || param.IsInOut; |
||||||
|
var paramType = param.Type; |
||||||
|
|
||||||
|
var ctx = new MarshalContext(Context, CurrentIndentation) |
||||||
|
{ |
||||||
|
Parameter = effectiveParam, |
||||||
|
ParameterIndex = paramIndex, |
||||||
|
ArgName = argName, |
||||||
|
Function = function |
||||||
|
}; |
||||||
|
|
||||||
|
var marshal = new CppMarshalManagedToNativePrinter(ctx); |
||||||
|
effectiveParam.Visit(marshal); |
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(marshal.Context.Return)) |
||||||
|
throw new Exception($"Cannot marshal argument of function '{function.QualifiedOriginalName}'"); |
||||||
|
|
||||||
|
if (isRef) |
||||||
|
{ |
||||||
|
var typePrinter = new CppTypePrinter(); |
||||||
|
var type = paramType.Visit(typePrinter); |
||||||
|
|
||||||
|
if (param.IsInOut) |
||||||
|
{ |
||||||
|
if (!string.IsNullOrWhiteSpace(marshal.Context.Before)) |
||||||
|
Write(marshal.Context.Before); |
||||||
|
|
||||||
|
WriteLine($"{type} {argName} = {marshal.Context.Return};"); |
||||||
|
} |
||||||
|
else |
||||||
|
WriteLine($"{type} {argName};"); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
if (!string.IsNullOrWhiteSpace(marshal.Context.Before)) |
||||||
|
Write(marshal.Context.Before); |
||||||
|
|
||||||
|
WriteLine($"auto {marshal.VarPrefix}{argName} = {marshal.Context.Return};"); |
||||||
|
paramMarshal.Prefix = marshal.ArgumentPrefix; |
||||||
|
} |
||||||
|
|
||||||
|
paramMarshal.Name = argName; |
||||||
|
return paramMarshal; |
||||||
|
} |
||||||
|
|
||||||
|
public void GenerateFunctionParams(List<ParamMarshal> @params) |
||||||
|
{ |
||||||
|
var names = @params.Select(param => |
||||||
|
string.IsNullOrWhiteSpace(param.Prefix) ? param.Name : (param.Prefix + param.Name)) |
||||||
|
.ToList(); |
||||||
|
|
||||||
|
Write(string.Join(", ", names)); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue