Browse Source

Initial C++ generator backend.

pull/1304/head
João Matos 5 years ago committed by João Matos
parent
commit
cfba72ce1b
  1. 5
      src/Generator/Driver.cs
  2. 204
      src/Generator/Generators/C/CCodeGenerator.cs
  3. 48
      src/Generator/Generators/C/CppGenerator.cs
  4. 609
      src/Generator/Generators/C/CppHeaders.cs
  5. 682
      src/Generator/Generators/C/CppMarshal.cs
  6. 626
      src/Generator/Generators/C/CppSources.cs
  7. 2
      src/Generator/Options.cs
  8. 25
      src/Generator/Types/TypeMap.cs

5
src/Generator/Driver.cs

@ -13,6 +13,7 @@ using CppSharp.Passes; @@ -13,6 +13,7 @@ using CppSharp.Passes;
using CppSharp.Utils;
using Microsoft.CSharp;
using CppSharp.Types;
using CppSharp.Generators.Cpp;
namespace CppSharp
{
@ -35,13 +36,15 @@ namespace CppSharp @@ -35,13 +36,15 @@ namespace CppSharp
{
switch (kind)
{
case GeneratorKind.CPlusPlus:
return new CppGenerator(Context);
case GeneratorKind.CLI:
return new CLIGenerator(Context);
case GeneratorKind.CSharp:
return new CSharpGenerator(Context);
}
return null;
throw new NotImplementedException();
}
void ValidateOptions()

204
src/Generator/Generators/C/CCodeGenerator.cs

@ -32,9 +32,14 @@ namespace CppSharp.Generators.C @@ -32,9 +32,14 @@ namespace CppSharp.Generators.C
: base(context, units)
{
VisitOptions.VisitPropertyAccessors = true;
typePrinter = new CppTypePrinter();
}
public override string FileExtension => "h";
public abstract override string FileExtension { get; }
public abstract override void Process();
public ISet<CInclude> Includes = new HashSet<CInclude>();
public virtual string QualifiedName(Declaration decl)
{
@ -44,7 +49,20 @@ namespace CppSharp.Generators.C @@ -44,7 +49,20 @@ namespace CppSharp.Generators.C
return decl.QualifiedName;
}
protected CppTypePrinter typePrinter = new CppTypePrinter();
public string QualifiedIdentifier(Declaration decl)
{
if (!string.IsNullOrEmpty(TranslationUnit.Module.OutputNamespace))
{
if (string.IsNullOrEmpty(decl.QualifiedName))
return $"{decl.TranslationUnit.Module.OutputNamespace}";
return $"{decl.TranslationUnit.Module.OutputNamespace}::{decl.QualifiedName}";
}
return decl.QualifiedName;
}
protected CppTypePrinter typePrinter;
public virtual CppTypePrinter CTypePrinter => typePrinter;
public bool IsCLIGenerator => Context.Options.GeneratorKind == GeneratorKind.CLI;
@ -67,16 +85,6 @@ namespace CppSharp.Generators.C @@ -67,16 +85,6 @@ namespace CppSharp.Generators.C
return decl.IsGenerated && !AlreadyVisited(decl);
}
public virtual string GetMethodIdentifier(Method method) => method.Name;
public override void GenerateMethodSpecifier(Method method, Class @class)
{
var retType = method.ReturnType.Visit(CTypePrinter);
Write($"{retType} {GetMethodIdentifier(method)}(");
Write(CTypePrinter.VisitParameters(method.Parameters));
Write(")");
}
public override bool VisitTypedefDecl(TypedefDecl typedef)
{
if (!VisitDeclaration(typedef))
@ -276,9 +284,181 @@ namespace CppSharp.Generators.C @@ -276,9 +284,181 @@ namespace CppSharp.Generators.C
public override bool VisitFieldDecl(Field field)
{
CTypePrinter.PushContext(TypePrinterContextKind.Native);
var typeName = field.Type.Visit(CTypePrinter);
CTypePrinter.PopContext();
PushBlock(BlockKind.Field, field);
WriteLine($"{typeName} {field.Name};");
PopBlock(NewLineKind.BeforeNextBlock);
return true;
}
public virtual string GetMethodIdentifier(Function function,
TypePrinterContextKind context = TypePrinterContextKind.Managed)
{
var method = function as Method;
if (method != null)
{
if (method.OperatorKind == CXXOperatorKind.Star)
{
CTypePrinter.PushContext(TypePrinterContextKind.Native);
var conversionType = method.ReturnType.Visit(CTypePrinter);
CTypePrinter.PopContext();
}
if (method.OperatorKind == CXXOperatorKind.Conversion ||
method.OperatorKind == CXXOperatorKind.ExplicitConversion)
{
CTypePrinter.PushContext(context);
var conversionType = method.ConversionType.Visit(CTypePrinter);
CTypePrinter.PopContext();
return "operator " + conversionType;
}
if (method.IsConstructor || method.IsDestructor)
{
var @class = (Class)method.Namespace;
return @class.Name;
}
}
return (context == TypePrinterContextKind.Managed) ?
function.Name : function.OriginalName;
}
public override void GenerateMethodSpecifier(Method method, Class @class)
{
var isHeaderFile = FileExtension == "h";
if (isHeaderFile)
{
if (method.IsVirtual || method.IsOverride)
Write("virtual ");
if (method.IsStatic)
Write("static ");
if (method.IsExplicit)
Write("explicit ");
}
if (method.IsConstructor || method.IsDestructor ||
method.OperatorKind == CXXOperatorKind.Conversion ||
method.OperatorKind == CXXOperatorKind.ExplicitConversion)
{
Write($"{GetMethodIdentifier(method)}(");
}
else
{
var returnType = method.ReturnType.Visit(CTypePrinter);
Write($"{returnType} {GetMethodIdentifier(method)}(");
}
GenerateMethodParameters(method);
Write(")");
if (method.IsOverride)
Write(" override");
}
public virtual void GenerateMethodParameters(Function function)
{
Write(CTypePrinter.VisitParameters(function.Parameters));
}
public override bool VisitMethodDecl(Method method)
{
PushBlock(BlockKind.Method, method);
GenerateMethodSpecifier(method, method.Namespace as Class);
Write(";");
PopBlock(NewLineKind.BeforeNextBlock);
return true;
}
public override bool VisitProperty(Property property)
{
if (!(property.HasGetter || property.HasSetter))
return false;
if (property.Field != null)
return false;
if (property.HasGetter)
GeneratePropertyGetter(property.GetMethod);
if (property.HasSetter)
GeneratePropertySetter(property.SetMethod);
//if (Options.GenerateMSDeclspecProperties)
//GenerateMSDeclspecProperty(property);
return true;
}
public virtual void GeneratePropertyAccessorSpecifier(Method method)
{
GenerateMethodSpecifier(method, method.Namespace as Class);
}
public virtual void GeneratePropertyGetter(Method method)
{
PushBlock(BlockKind.Method, method);
GeneratePropertyAccessorSpecifier(method);
WriteLine(";");
PopBlock(NewLineKind.BeforeNextBlock);
}
public virtual void GeneratePropertySetter(Method method)
{
PushBlock(BlockKind.Method, method);
GeneratePropertyAccessorSpecifier(method);
WriteLine(";");
PopBlock(NewLineKind.BeforeNextBlock);
}
private void GenerateMSDeclspecProperty(Property property)
{
PushBlock(BlockKind.Property, property);
if (property.IsStatic)
Write("static ");
if (property.IsIndexer)
{
//GenerateIndexer(property);
//throw new System.NotImplementedException();
}
else
{
var blocks = new List<string>();
if (property.HasGetter)
blocks.Add($"get = {property.GetMethod.Name}");
if (property.HasSetter)
blocks.Add($"put = {property.SetMethod.Name}");
var getterSetter = string.Join(",", blocks);
var type = property.QualifiedType.Visit(CTypePrinter);
WriteLine($"__declspec(property({getterSetter})) {type} {property.Name};");
}
PopBlock(NewLineKind.BeforeNextBlock);
}
static readonly List<string> CReservedKeywords = new List<string> {
// C99 6.4.1: Keywords.
"auto", "break", "case", "char", "const", "continue", "default",

48
src/Generator/Generators/C/CppGenerator.cs

@ -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();
}
}
}

609
src/Generator/Generators/C/CppHeaders.cs

@ -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;
}
}
}

682
src/Generator/Generators/C/CppMarshal.cs

@ -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();
}
}
}

626
src/Generator/Generators/C/CppSources.cs

@ -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));
}
}
}

2
src/Generator/Options.cs

@ -127,6 +127,8 @@ namespace CppSharp @@ -127,6 +127,8 @@ namespace CppSharp
public bool IsCSharpGenerator => GeneratorKind == GeneratorKind.CSharp;
public bool IsCppGenerator => GeneratorKind == GeneratorKind.CPlusPlus;
public bool IsCLIGenerator => GeneratorKind == GeneratorKind.CLI;
public readonly List<string> DependentNameSpaces = new List<string>();

25
src/Generator/Types/TypeMap.cs

@ -3,6 +3,7 @@ using CppSharp.AST; @@ -3,6 +3,7 @@ using CppSharp.AST;
using CppSharp.Generators;
using CppSharp.Generators.AST;
using CppSharp.Generators.CLI;
using CppSharp.Generators.Cpp;
using CppSharp.Generators.CSharp;
using Attribute = System.Attribute;
using Type = CppSharp.AST.Type;
@ -99,6 +100,30 @@ namespace CppSharp.Types @@ -99,6 +100,30 @@ namespace CppSharp.Types
}
#endregion
#region C++ backend
public virtual Type CppSignatureType(TypePrinterContext ctx)
{
return new CILType(typeof(object));
}
public virtual void CppTypeReference(CLITypeReference collector, ASTRecord<Declaration> record)
{
throw new NotImplementedException();
}
public virtual void CppMarshalToNative(MarshalContext ctx)
{
ctx.Return.Write(ctx.Parameter.Name);
}
public virtual void CppMarshalToManaged(MarshalContext ctx)
{
ctx.Return.Write(ctx.ReturnVarName);
}
#endregion
}
public interface ITypeMapDatabase

Loading…
Cancel
Save