mirror of https://github.com/mono/CppSharp.git
8 changed files with 2188 additions and 13 deletions
@ -0,0 +1,48 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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