mirror of https://github.com/mono/CppSharp.git
40 changed files with 3601 additions and 135 deletions
@ -0,0 +1,40 @@ |
|||||||
|
using System.Collections.Generic; |
||||||
|
using CppSharp.AST; |
||||||
|
using CppSharp.Generators.Cpp; |
||||||
|
|
||||||
|
namespace CppSharp.Generators.C |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// C++ generator responsible for driving the generation of source and
|
||||||
|
/// header files.
|
||||||
|
/// </summary>
|
||||||
|
public class CGenerator : Generator |
||||||
|
{ |
||||||
|
private readonly CppTypePrinter typePrinter; |
||||||
|
|
||||||
|
public CGenerator(BindingContext context) : base(context) |
||||||
|
{ |
||||||
|
typePrinter = new CppTypePrinter(Context); |
||||||
|
} |
||||||
|
|
||||||
|
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; |
||||||
|
|
||||||
|
protected override string TypePrinterDelegate(Type type) |
||||||
|
{ |
||||||
|
return type.Visit(typePrinter).ToString(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,35 @@ |
|||||||
|
using System.Collections.Generic; |
||||||
|
using CppSharp.AST; |
||||||
|
using CppSharp.Generators.Cpp; |
||||||
|
|
||||||
|
namespace CppSharp.Generators.C |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// N-API generator responsible for driving the generation of binding files.
|
||||||
|
/// N-API documentation: https://nodejs.org/api/n-api.html
|
||||||
|
/// </summary>
|
||||||
|
public class NAPIGenerator : CppGenerator |
||||||
|
{ |
||||||
|
public NAPIGenerator(BindingContext context) : base(context) |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
public override List<CodeGenerator> Generate(IEnumerable<TranslationUnit> units) |
||||||
|
{ |
||||||
|
var outputs = new List<CodeGenerator>(); |
||||||
|
|
||||||
|
var header = new NAPIHeaders(Context, units); |
||||||
|
outputs.Add(header); |
||||||
|
|
||||||
|
var source = new CppSources(Context, units); |
||||||
|
outputs.Add(source); |
||||||
|
|
||||||
|
return outputs; |
||||||
|
} |
||||||
|
|
||||||
|
public override GeneratorOutput GenerateModule(Module module) |
||||||
|
{ |
||||||
|
return base.GenerateModule(module); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,23 @@ |
|||||||
|
using System.Collections.Generic; |
||||||
|
using CppSharp.AST; |
||||||
|
|
||||||
|
namespace CppSharp.Generators.Cpp |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Generates Node N-API C/C++ header files.
|
||||||
|
/// N-API documentation: https://nodejs.org/api/n-api.html
|
||||||
|
/// </summary>
|
||||||
|
public class NAPIHeaders : CppHeaders |
||||||
|
{ |
||||||
|
public NAPIHeaders(BindingContext context, IEnumerable<TranslationUnit> units) |
||||||
|
: base(context, units) |
||||||
|
{ |
||||||
|
CTypePrinter.PushContext(TypePrinterContextKind.Managed); |
||||||
|
} |
||||||
|
|
||||||
|
public override void Process() |
||||||
|
{ |
||||||
|
base.Process(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,37 @@ |
|||||||
|
using System.Collections.Generic; |
||||||
|
using CppSharp.AST; |
||||||
|
using CppSharp.Generators.C; |
||||||
|
|
||||||
|
namespace CppSharp.Generators.Cpp |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Generates Node N-API C/C++ module init files.
|
||||||
|
/// N-API documentation: https://nodejs.org/api/n-api.html
|
||||||
|
/// </summary>
|
||||||
|
public class NAPIModule : CCodeGenerator |
||||||
|
{ |
||||||
|
public NAPIModule(BindingContext context, IEnumerable<TranslationUnit> units) |
||||||
|
: base(context, units) |
||||||
|
{ |
||||||
|
CTypePrinter.PushContext(TypePrinterContextKind.Managed); |
||||||
|
} |
||||||
|
|
||||||
|
public override string FileExtension { get; } = "cpp"; |
||||||
|
|
||||||
|
public override void Process() |
||||||
|
{ |
||||||
|
var include = new CInclude() |
||||||
|
{ |
||||||
|
File = "node_api.h", |
||||||
|
Kind = CInclude.IncludeKind.Angled |
||||||
|
}; |
||||||
|
|
||||||
|
WriteInclude(include); |
||||||
|
|
||||||
|
WriteLine("NAPI_MODULE_INIT()"); |
||||||
|
WriteOpenBraceAndIndent(); |
||||||
|
|
||||||
|
UnindentAndWriteCloseBrace(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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(Context); |
||||||
|
} |
||||||
|
|
||||||
|
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,632 @@ |
|||||||
|
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) |
||||||
|
{ |
||||||
|
CTypePrinter.PushContext(TypePrinterContextKind.Managed); |
||||||
|
} |
||||||
|
|
||||||
|
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\""); |
||||||
|
WriteLine("#include \"FastDelegates.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 override bool VisitDeclContext(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); |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
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(); |
||||||
|
} |
||||||
|
|
||||||
|
VisitDeclContext(@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(); |
||||||
|
VisitDeclContext(@class); |
||||||
|
Unindent(); |
||||||
|
|
||||||
|
if (CppGenerator.ShouldGenerateClassNativeField(@class)) |
||||||
|
GenerateClassNativeField(@class); |
||||||
|
|
||||||
|
GenerateClassConstructors(@class); |
||||||
|
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) |
||||||
|
{ |
||||||
|
PushBlock(); |
||||||
|
|
||||||
|
var nativeInstanceField = new Field() |
||||||
|
{ |
||||||
|
Name = Helpers.InstanceIdentifier, |
||||||
|
QualifiedType = new QualifiedType(new PointerType(new QualifiedType(new TagType(@class)))), |
||||||
|
Namespace = @class |
||||||
|
}; |
||||||
|
|
||||||
|
Indent(); |
||||||
|
CTypePrinter.PushContext(TypePrinterContextKind.Native); |
||||||
|
nativeInstanceField.Visit(this); |
||||||
|
CTypePrinter.PopContext(); |
||||||
|
Unindent(); |
||||||
|
|
||||||
|
PopBlock(NewLineKind.BeforeNextBlock); |
||||||
|
|
||||||
|
/*var nativeInstanceProperty = new Property() |
||||||
|
{ |
||||||
|
Name = Helpers.InstanceIdentifier, |
||||||
|
QualifiedType = |
||||||
|
}; |
||||||
|
|
||||||
|
nativeInstanceProperty.Visit(this);*/ |
||||||
|
} |
||||||
|
|
||||||
|
public virtual void GenerateClassGenericMethods(Class @class) |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
public void GenerateClassConstructors(Class @class) |
||||||
|
{ |
||||||
|
if (@class.IsStatic) |
||||||
|
return; |
||||||
|
|
||||||
|
Indent(); |
||||||
|
|
||||||
|
CTypePrinter.PushContext(TypePrinterContextKind.Native); |
||||||
|
var classNativeName = @class.Visit(CTypePrinter); |
||||||
|
CTypePrinter.PopContext(); |
||||||
|
|
||||||
|
WriteLine($"{@class.Name}({classNativeName}* instance);"); |
||||||
|
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 fieldType = field.Type.Visit(CTypePrinter); |
||||||
|
WriteLine($"{fieldType} {field.Name};"); |
||||||
|
|
||||||
|
PopBlock(); |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public void GenerateClassEvents(Class @class) |
||||||
|
{ |
||||||
|
Indent(); |
||||||
|
|
||||||
|
foreach (var @event in @class.Events) |
||||||
|
{ |
||||||
|
if (!@event.IsGenerated) continue; |
||||||
|
@event.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
Unindent(); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitEvent(Event @event) |
||||||
|
{ |
||||||
|
PushBlock(BlockKind.Event, @event); |
||||||
|
|
||||||
|
GenerateDeclarationCommon(@event); |
||||||
|
|
||||||
|
var type = @event.Type.Visit(CTypePrinter); |
||||||
|
type = type.ToString().Replace("()", string.Empty); |
||||||
|
|
||||||
|
WriteLine($"fastdelegate::FastDelegate<{type}> {@event.Name};"); |
||||||
|
|
||||||
|
PopBlock(NewLineKind.BeforeNextBlock); |
||||||
|
|
||||||
|
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.BaseClass)}"); |
||||||
|
} |
||||||
|
|
||||||
|
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); |
||||||
|
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.CompleteDeclaration == null && @class.IsIncomplete); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,709 @@ |
|||||||
|
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(Context.Context) |
||||||
|
{ 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(Context.Context); |
||||||
|
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)) |
||||||
|
{ |
||||||
|
var typePrinter = new CppTypePrinter(Context.Context); |
||||||
|
var typeName = typePrinter.VisitDeclaration(decl); |
||||||
|
var typeName2 = decl.Type.Visit(typePrinter); |
||||||
|
Context.Return.Write(typeName); |
||||||
|
//return typeName;
|
||||||
|
//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 (@class.CompleteDeclaration != null) |
||||||
|
{ |
||||||
|
WriteClassInstance(@class.CompleteDeclaration as Class, instance); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
if (!Context.ReturnType.Type.Desugar().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(Context.Context); |
||||||
|
typePrinter.PushContext(TypePrinterContextKind.Managed); |
||||||
|
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(Context.Context); |
||||||
|
cppTypePrinter.PushContext(TypePrinterContextKind.Managed); |
||||||
|
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(Context.Context); |
||||||
|
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: |
||||||
|
case PrimitiveType.WideChar: |
||||||
|
Context.Return.Write(Context.Parameter.Name); |
||||||
|
return true; |
||||||
|
default: |
||||||
|
throw new NotImplementedException(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
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)) |
||||||
|
{ |
||||||
|
var typePrinter = new CppTypePrinter(Context.Context); |
||||||
|
typePrinter.PushContext(TypePrinterContextKind.Native); |
||||||
|
var declName = decl.Visit(typePrinter); |
||||||
|
typePrinter.PopContext(); |
||||||
|
|
||||||
|
// Use the original typedef name if available, otherwise just use the function pointer type
|
||||||
|
string cppTypeName; |
||||||
|
if (!decl.IsSynthetized) |
||||||
|
{ |
||||||
|
cppTypeName = "::" + typedef.Declaration.QualifiedOriginalName; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
cppTypeName = decl.Type.Visit(typePrinter, 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 isPointer = paramType.SkipPointerRefs().IsPointer(); |
||||||
|
var deref = isPointer ? "->" : "."; |
||||||
|
var instance = $"(::{@class.QualifiedOriginalName}*)" + |
||||||
|
$"{Context.Parameter.Name}{deref}{Helpers.InstanceIdentifier}"; |
||||||
|
|
||||||
|
if (isPointer) |
||||||
|
Context.Return.Write($"{Context.Parameter.Name} ? {instance} : nullptr"); |
||||||
|
else |
||||||
|
Context.Return.Write($"{instance}"); |
||||||
|
} |
||||||
|
|
||||||
|
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,725 @@ |
|||||||
|
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; |
||||||
|
using CppSharp.Types; |
||||||
|
|
||||||
|
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) |
||||||
|
{ |
||||||
|
CTypePrinter.PushContext(TypePrinterContextKind.Managed); |
||||||
|
} |
||||||
|
|
||||||
|
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(); |
||||||
|
|
||||||
|
VisitNamespace(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 override bool VisitClassDecl(Class @class) |
||||||
|
{ |
||||||
|
if (@class.IsDynamic) |
||||||
|
{ |
||||||
|
PushBlock(); |
||||||
|
var overridesClassGen = new OverridesClassGenerator(Context); |
||||||
|
overridesClassGen.VisitClassDecl(@class); |
||||||
|
AddBlock(overridesClassGen.RootBlock); |
||||||
|
PopBlock(NewLineKind.BeforeNextBlock); |
||||||
|
} |
||||||
|
|
||||||
|
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(); |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
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 && property.SetMethod != null) |
||||||
|
GeneratePropertySetter(property.SetMethod); |
||||||
|
|
||||||
|
PopBlock(NewLineKind.Never); |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public override void GeneratePropertyGetter(Method method) |
||||||
|
{ |
||||||
|
PushBlock(BlockKind.Method, method); |
||||||
|
|
||||||
|
GeneratePropertyAccessorSpecifier(method); |
||||||
|
NewLine(); |
||||||
|
|
||||||
|
WriteOpenBraceAndIndent(); |
||||||
|
|
||||||
|
GenerateFunctionCall(method); |
||||||
|
|
||||||
|
UnindentAndWriteCloseBrace(); |
||||||
|
NewLine(); |
||||||
|
|
||||||
|
PopBlock(NewLineKind.BeforeNextBlock); |
||||||
|
} |
||||||
|
|
||||||
|
public override void GeneratePropertySetter(Method method) |
||||||
|
{ |
||||||
|
PushBlock(BlockKind.Method, method); |
||||||
|
|
||||||
|
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})"); |
||||||
|
GenerateClassConstructorBase(@class); |
||||||
|
|
||||||
|
WriteOpenBraceAndIndent(); |
||||||
|
|
||||||
|
WriteLine($"{Helpers.InstanceIdentifier} = {ClassCtorInstanceParamIdentifier};"); |
||||||
|
|
||||||
|
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($": {QualifiedIdentifier(baseClass)}("); |
||||||
|
|
||||||
|
// We cast the value to the base class type since otherwise there
|
||||||
|
// could be ambiguous call to overloaded constructors.
|
||||||
|
CTypePrinter.PushContext(TypePrinterContextKind.Native); |
||||||
|
var nativeTypeName = baseClass.Visit(CTypePrinter); |
||||||
|
CTypePrinter.PopContext(); |
||||||
|
Write($"({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); |
||||||
|
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) |
||||||
|
{ |
||||||
|
if (!@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 @class = function.Namespace as Class; |
||||||
|
|
||||||
|
var property = method?.AssociatedDeclaration as Property; |
||||||
|
var field = property?.Field; |
||||||
|
if (field != null) |
||||||
|
{ |
||||||
|
Write($"((::{@class.QualifiedOriginalName}*){Helpers.InstanceIdentifier})->"); |
||||||
|
Write($"{field.OriginalName}"); |
||||||
|
|
||||||
|
var isGetter = property.GetMethod == method; |
||||||
|
if (isGetter) |
||||||
|
WriteLine(";"); |
||||||
|
else |
||||||
|
WriteLine($" = {@params[0].Name};"); |
||||||
|
} |
||||||
|
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 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 type = paramType.Visit(CTypePrinter); |
||||||
|
|
||||||
|
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)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public class OverridesClassGenerator : CCodeGenerator |
||||||
|
{ |
||||||
|
public OverridesClassGenerator(BindingContext context) |
||||||
|
: base(context) |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitClassDecl(Class @class) |
||||||
|
{ |
||||||
|
CTypePrinter.PushContext(TypePrinterContextKind.Native); |
||||||
|
var typeName = @class.Visit(CTypePrinter); |
||||||
|
|
||||||
|
WriteLine($"class _{@class.Name} : public {typeName}"); |
||||||
|
WriteOpenBraceAndIndent(); |
||||||
|
|
||||||
|
var uniqueMethods = new HashSet<Method>(); |
||||||
|
|
||||||
|
foreach (var component in @class.Layout.Layout.Components) |
||||||
|
{ |
||||||
|
var method = component.Method; |
||||||
|
if (method == null) |
||||||
|
continue; |
||||||
|
|
||||||
|
if (!method.IsVirtual || (method.GenerationKind == GenerationKind.None)) |
||||||
|
continue; |
||||||
|
|
||||||
|
if (!uniqueMethods.Add(method)) |
||||||
|
continue; |
||||||
|
|
||||||
|
method = new Method(component.Method) |
||||||
|
{ |
||||||
|
IsOverride = true |
||||||
|
}; |
||||||
|
|
||||||
|
if (method.IsConstructor || method.IsDestructor) |
||||||
|
continue; |
||||||
|
|
||||||
|
uniqueMethods.Add(method); |
||||||
|
|
||||||
|
PushBlock(BlockKind.Method, method); |
||||||
|
GenerateMethodSpecifier(method, MethodSpecifierKind.Declaration); |
||||||
|
NewLine(); |
||||||
|
WriteOpenBraceAndIndent(); |
||||||
|
|
||||||
|
DeclMap declMap; |
||||||
|
if (Context.DeclMaps.FindDeclMap(method, out declMap)) |
||||||
|
{ |
||||||
|
declMap.Declaration = method; |
||||||
|
declMap.DeclarationContext = @class; |
||||||
|
declMap.Generate(this); |
||||||
|
} |
||||||
|
|
||||||
|
var needsReturn = !method.ReturnType.Type.IsPrimitiveType(PrimitiveType.Void); |
||||||
|
if (needsReturn) |
||||||
|
{ |
||||||
|
var returnType = method.ReturnType.Visit(CTypePrinter); |
||||||
|
Write($"{returnType} {Helpers.ReturnIdentifier} = "); |
||||||
|
} |
||||||
|
|
||||||
|
var parameters = string.Join(", ", method.Parameters.Select(p => p.Name)); |
||||||
|
WriteLine($"this->{method.OriginalName}({parameters});"); |
||||||
|
|
||||||
|
if (needsReturn) |
||||||
|
WriteLine($"return {Helpers.ReturnIdentifier};"); |
||||||
|
|
||||||
|
UnindentAndWriteCloseBrace(); |
||||||
|
PopBlock(NewLineKind.BeforeNextBlock); |
||||||
|
} |
||||||
|
|
||||||
|
Unindent(); |
||||||
|
WriteLine("};"); |
||||||
|
|
||||||
|
CTypePrinter.PopContext(); |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,734 @@ |
|||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Linq; |
||||||
|
using CppSharp.AST; |
||||||
|
using CppSharp.AST.Extensions; |
||||||
|
using CppSharp.Types; |
||||||
|
|
||||||
|
namespace CppSharp.Generators.C |
||||||
|
{ |
||||||
|
public enum CppTypePrintFlavorKind |
||||||
|
{ |
||||||
|
C, |
||||||
|
Cpp, |
||||||
|
ObjC |
||||||
|
} |
||||||
|
|
||||||
|
public class CppTypePrinter : TypePrinter |
||||||
|
{ |
||||||
|
public CppTypePrintFlavorKind PrintFlavorKind { get; set; } |
||||||
|
public bool PrintLogicalNames { get; set; } |
||||||
|
public bool PrintTypeQualifiers { get; set; } |
||||||
|
public bool PrintTypeModifiers { get; set; } |
||||||
|
public bool PrintVariableArrayAsPointers { get; set; } |
||||||
|
|
||||||
|
public CppTypePrinter(BindingContext context) : base(TypePrinterContextKind.Native) |
||||||
|
{ |
||||||
|
Context = context; |
||||||
|
PrintFlavorKind = CppTypePrintFlavorKind.Cpp; |
||||||
|
ScopeKind = TypePrintScopeKind.GlobalQualified; |
||||||
|
PrintTypeQualifiers = true; |
||||||
|
PrintTypeModifiers = true; |
||||||
|
} |
||||||
|
|
||||||
|
public BindingContext Context { get; private set; } |
||||||
|
public TypeMapDatabase TypeMapDatabase => Context.TypeMaps; |
||||||
|
public DriverOptions Options => Context.Options; |
||||||
|
|
||||||
|
public bool ResolveTypeMaps { get; set; } = true; |
||||||
|
public bool ResolveTypedefs { get; set; } |
||||||
|
|
||||||
|
public bool FindTypeMap(CppSharp.AST.Type type, out TypePrinterResult result) |
||||||
|
{ |
||||||
|
result = null; |
||||||
|
|
||||||
|
if (!ResolveTypeMaps) |
||||||
|
return false; |
||||||
|
|
||||||
|
TypeMap typeMap; |
||||||
|
if (!TypeMapDatabase.FindTypeMap(type, out typeMap) || typeMap.IsIgnored) |
||||||
|
return false; |
||||||
|
|
||||||
|
var typePrinterContext = new TypePrinterContext |
||||||
|
{ |
||||||
|
Type = type, |
||||||
|
Kind = Kind, |
||||||
|
MarshalKind = MarshalKind |
||||||
|
}; |
||||||
|
|
||||||
|
var typePrinter = new CppTypePrinter(Context) |
||||||
|
{ |
||||||
|
PrintFlavorKind = PrintFlavorKind, |
||||||
|
ScopeKind = ScopeKind, |
||||||
|
PrintTypeQualifiers = PrintTypeQualifiers, |
||||||
|
PrintTypeModifiers = PrintTypeModifiers, |
||||||
|
ResolveTypeMaps = false |
||||||
|
}; |
||||||
|
typePrinter.PushContext(ContextKind); |
||||||
|
|
||||||
|
var typeName = typeMap.CppSignatureType(typePrinterContext).Visit(typePrinter); |
||||||
|
result = new TypePrinterResult(typeName) { TypeMap = typeMap }; |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitTagType(TagType tag, |
||||||
|
TypeQualifiers quals) |
||||||
|
{ |
||||||
|
TypePrinterResult result; |
||||||
|
if (FindTypeMap(tag, out result)) |
||||||
|
return result; |
||||||
|
|
||||||
|
var qual = GetStringQuals(quals); |
||||||
|
return $"{qual}{tag.Declaration.Visit(this)}"; |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitArrayType(ArrayType array, |
||||||
|
TypeQualifiers quals) |
||||||
|
{ |
||||||
|
var arraySuffix = string.Empty; |
||||||
|
|
||||||
|
switch (array.SizeType) |
||||||
|
{ |
||||||
|
case ArrayType.ArraySize.Constant: |
||||||
|
arraySuffix = $"[{array.Size}]"; |
||||||
|
break; |
||||||
|
case ArrayType.ArraySize.Variable: |
||||||
|
case ArrayType.ArraySize.Dependent: |
||||||
|
case ArrayType.ArraySize.Incomplete: |
||||||
|
arraySuffix = $"{(PrintVariableArrayAsPointers ? "*" : "[]")}"; |
||||||
|
break; |
||||||
|
default: |
||||||
|
throw new NotImplementedException(); |
||||||
|
} |
||||||
|
|
||||||
|
var result = new TypePrinterResult |
||||||
|
{ |
||||||
|
Type = array.QualifiedType.Visit(this), |
||||||
|
NameSuffix = new System.Text.StringBuilder(arraySuffix) |
||||||
|
}; |
||||||
|
|
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
private static string ConvertModifierToString(PointerType.TypeModifier modifier) |
||||||
|
{ |
||||||
|
switch (modifier) |
||||||
|
{ |
||||||
|
case PointerType.TypeModifier.Value: return "[]"; |
||||||
|
case PointerType.TypeModifier.Pointer: return "*"; |
||||||
|
case PointerType.TypeModifier.LVReference: return "&"; |
||||||
|
case PointerType.TypeModifier.RVReference: return "&&"; |
||||||
|
} |
||||||
|
|
||||||
|
return string.Empty; |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitPointerType(PointerType pointer, |
||||||
|
TypeQualifiers quals) |
||||||
|
{ |
||||||
|
TypePrinterResult result; |
||||||
|
if (FindTypeMap(pointer, out result)) |
||||||
|
return result; |
||||||
|
|
||||||
|
var pointeeType = pointer.Pointee.Visit(this, pointer.QualifiedPointee.Qualifiers); |
||||||
|
if (pointeeType.TypeMap != null) |
||||||
|
return pointeeType; |
||||||
|
|
||||||
|
var mod = PrintTypeModifiers ? ConvertModifierToString(pointer.Modifier) : string.Empty; |
||||||
|
pointeeType.NamePrefix.Append(mod); |
||||||
|
|
||||||
|
var qual = GetStringQuals(quals, false); |
||||||
|
if (!string.IsNullOrEmpty(qual)) |
||||||
|
pointeeType.NamePrefix.Append(' ').Append(qual); |
||||||
|
|
||||||
|
return pointeeType; |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitMemberPointerType(MemberPointerType member, |
||||||
|
TypeQualifiers quals) |
||||||
|
{ |
||||||
|
return string.Empty; |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitBuiltinType(BuiltinType builtin, |
||||||
|
TypeQualifiers quals) |
||||||
|
{ |
||||||
|
var qual = GetStringQuals(quals); |
||||||
|
return $"{qual}{VisitPrimitiveType(builtin.Type)}"; |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitPrimitiveType(PrimitiveType primitive, |
||||||
|
TypeQualifiers quals) |
||||||
|
{ |
||||||
|
var qual = GetStringQuals(quals); |
||||||
|
return $"{qual}{VisitPrimitiveType(primitive)}"; |
||||||
|
} |
||||||
|
|
||||||
|
public virtual TypePrinterResult VisitPrimitiveType(PrimitiveType primitive) |
||||||
|
{ |
||||||
|
switch (primitive) |
||||||
|
{ |
||||||
|
case PrimitiveType.Bool: return "bool"; |
||||||
|
case PrimitiveType.Void: return "void"; |
||||||
|
case PrimitiveType.Char16: return "char16_t"; |
||||||
|
case PrimitiveType.Char32: return "char32_t"; |
||||||
|
case PrimitiveType.WideChar: return "wchar_t"; |
||||||
|
case PrimitiveType.Char: return "char"; |
||||||
|
case PrimitiveType.SChar: return "signed char"; |
||||||
|
case PrimitiveType.UChar: return "unsigned char"; |
||||||
|
case PrimitiveType.Short: return "short"; |
||||||
|
case PrimitiveType.UShort: return "unsigned short"; |
||||||
|
case PrimitiveType.Int: return "int"; |
||||||
|
case PrimitiveType.UInt: return "unsigned int"; |
||||||
|
case PrimitiveType.Long: return "long"; |
||||||
|
case PrimitiveType.ULong: return "unsigned long"; |
||||||
|
case PrimitiveType.LongLong: return "long long"; |
||||||
|
case PrimitiveType.ULongLong: return "unsigned long long"; |
||||||
|
case PrimitiveType.Int128: return "__int128_t"; |
||||||
|
case PrimitiveType.UInt128: return "__uint128_t"; |
||||||
|
case PrimitiveType.Half: return "__fp16"; |
||||||
|
case PrimitiveType.Float: return "float"; |
||||||
|
case PrimitiveType.Double: return "double"; |
||||||
|
case PrimitiveType.LongDouble: return "long double"; |
||||||
|
case PrimitiveType.Float128: return "__float128"; |
||||||
|
case PrimitiveType.IntPtr: return "void*"; |
||||||
|
case PrimitiveType.UIntPtr: return "uintptr_t"; |
||||||
|
case PrimitiveType.Null: |
||||||
|
return PrintFlavorKind == CppTypePrintFlavorKind.Cpp ? |
||||||
|
"std::nullptr_t" : "NULL"; |
||||||
|
case PrimitiveType.String: |
||||||
|
{ |
||||||
|
switch (PrintFlavorKind) |
||||||
|
{ |
||||||
|
case CppTypePrintFlavorKind.C: |
||||||
|
return "const char*"; |
||||||
|
case CppTypePrintFlavorKind.Cpp: |
||||||
|
return "std::string"; |
||||||
|
case CppTypePrintFlavorKind.ObjC: |
||||||
|
return "NSString"; |
||||||
|
default: |
||||||
|
throw new ArgumentOutOfRangeException(); |
||||||
|
} |
||||||
|
} |
||||||
|
case PrimitiveType.Decimal: |
||||||
|
{ |
||||||
|
switch (PrintFlavorKind) |
||||||
|
{ |
||||||
|
case CppTypePrintFlavorKind.C: |
||||||
|
case CppTypePrintFlavorKind.Cpp: |
||||||
|
return "_Decimal32"; |
||||||
|
case CppTypePrintFlavorKind.ObjC: |
||||||
|
return "NSDecimalNumber"; |
||||||
|
default: |
||||||
|
throw new ArgumentOutOfRangeException(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
throw new NotSupportedException(); |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitTypedefType(TypedefType typedef, |
||||||
|
TypeQualifiers quals) |
||||||
|
{ |
||||||
|
TypePrinterResult result; |
||||||
|
|
||||||
|
FunctionType func; |
||||||
|
if (ResolveTypedefs && !typedef.Declaration.Type.IsPointerTo(out func)) |
||||||
|
result = typedef.Declaration.QualifiedType.Visit(this); |
||||||
|
else |
||||||
|
result = typedef.Declaration.Visit(this); |
||||||
|
|
||||||
|
var qual = GetStringQuals(quals); |
||||||
|
|
||||||
|
// In the case of const references to const typedefs, we could end up printing
|
||||||
|
// a double const.
|
||||||
|
//
|
||||||
|
// As an example, consider the following code:
|
||||||
|
//
|
||||||
|
// typedef const T const_t;
|
||||||
|
// foo(const const_t&p) { }
|
||||||
|
//
|
||||||
|
if (!result.Type.StartsWith("const ")) |
||||||
|
result.Type = $"{qual}{result.Type}"; |
||||||
|
|
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitAttributedType(AttributedType attributed, |
||||||
|
TypeQualifiers quals) |
||||||
|
{ |
||||||
|
return attributed.Modified.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitDecayedType(DecayedType decayed, |
||||||
|
TypeQualifiers quals) |
||||||
|
{ |
||||||
|
return decayed.Decayed.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitTemplateSpecializationType( |
||||||
|
TemplateSpecializationType template, TypeQualifiers quals) |
||||||
|
{ |
||||||
|
var specialization = template.GetClassTemplateSpecialization(); |
||||||
|
if (specialization == null) |
||||||
|
return string.Empty; |
||||||
|
|
||||||
|
var qual = GetStringQuals(quals); |
||||||
|
return $"{qual}{VisitClassTemplateSpecializationDecl(specialization)}"; |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitDependentTemplateSpecializationType( |
||||||
|
DependentTemplateSpecializationType template, TypeQualifiers quals) |
||||||
|
{ |
||||||
|
if (template.Desugared.Type != null) |
||||||
|
return template.Desugared.Visit(this); |
||||||
|
return string.Empty; |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitTemplateParameterType( |
||||||
|
TemplateParameterType param, TypeQualifiers quals) |
||||||
|
{ |
||||||
|
if (param.Parameter == null || param.Parameter.Name == null) |
||||||
|
return string.Empty; |
||||||
|
|
||||||
|
return param.Parameter.Name; |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitTemplateParameterSubstitutionType( |
||||||
|
TemplateParameterSubstitutionType param, TypeQualifiers quals) |
||||||
|
{ |
||||||
|
return param.Replacement.Type.Visit(this, quals); |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitInjectedClassNameType( |
||||||
|
InjectedClassNameType injected, TypeQualifiers quals) |
||||||
|
{ |
||||||
|
return injected.Class.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitDependentNameType( |
||||||
|
DependentNameType dependent, TypeQualifiers quals) |
||||||
|
{ |
||||||
|
return dependent.Qualifier.Type != null ? |
||||||
|
dependent.Qualifier.Visit(this).Type : string.Empty; |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitPackExpansionType( |
||||||
|
PackExpansionType packExpansionType, TypeQualifiers quals) |
||||||
|
{ |
||||||
|
return string.Empty; |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitUnaryTransformType( |
||||||
|
UnaryTransformType unaryTransformType, TypeQualifiers quals) |
||||||
|
{ |
||||||
|
if (unaryTransformType.Desugared.Type != null) |
||||||
|
return unaryTransformType.Desugared.Visit(this); |
||||||
|
return unaryTransformType.BaseType.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitVectorType(VectorType vectorType, |
||||||
|
TypeQualifiers quals) |
||||||
|
{ |
||||||
|
// an incomplete implementation but we'd hardly need anything better
|
||||||
|
return "__attribute__()"; |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitCILType(CILType type, TypeQualifiers quals) |
||||||
|
{ |
||||||
|
if (type.Type == typeof(string)) |
||||||
|
return quals.IsConst ? "const char*" : "char*"; |
||||||
|
|
||||||
|
switch (System.Type.GetTypeCode(type.Type)) |
||||||
|
{ |
||||||
|
case TypeCode.Boolean: |
||||||
|
return VisitBuiltinType(new BuiltinType(PrimitiveType.Bool), quals); |
||||||
|
case TypeCode.Char: |
||||||
|
case TypeCode.SByte: |
||||||
|
case TypeCode.Byte: |
||||||
|
return VisitBuiltinType(new BuiltinType(PrimitiveType.Char), quals); |
||||||
|
case TypeCode.Int16: |
||||||
|
return VisitBuiltinType(new BuiltinType(PrimitiveType.Short), quals); |
||||||
|
case TypeCode.UInt16: |
||||||
|
return VisitBuiltinType(new BuiltinType(PrimitiveType.UShort), quals); |
||||||
|
case TypeCode.Int32: |
||||||
|
return VisitBuiltinType(new BuiltinType(PrimitiveType.Int), quals); |
||||||
|
case TypeCode.UInt32: |
||||||
|
return VisitBuiltinType(new BuiltinType(PrimitiveType.UInt), quals); |
||||||
|
case TypeCode.Int64: |
||||||
|
return VisitBuiltinType(new BuiltinType(PrimitiveType.Long), quals); |
||||||
|
case TypeCode.UInt64: |
||||||
|
return VisitBuiltinType(new BuiltinType(PrimitiveType.ULong), quals); |
||||||
|
case TypeCode.Single: |
||||||
|
return VisitBuiltinType(new BuiltinType(PrimitiveType.Float), quals); |
||||||
|
case TypeCode.Double: |
||||||
|
return VisitBuiltinType(new BuiltinType(PrimitiveType.Double), quals); |
||||||
|
case TypeCode.String: |
||||||
|
return quals.IsConst ? "const char*" : "char*"; |
||||||
|
} |
||||||
|
|
||||||
|
return "void*"; |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitUnsupportedType(UnsupportedType type, |
||||||
|
TypeQualifiers quals) |
||||||
|
{ |
||||||
|
return type.Description; |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitDeclaration(Declaration decl, |
||||||
|
TypeQualifiers quals) |
||||||
|
{ |
||||||
|
return VisitDeclaration(decl); |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitFunctionType(FunctionType function, |
||||||
|
TypeQualifiers quals) |
||||||
|
{ |
||||||
|
var arguments = function.Parameters; |
||||||
|
var returnType = function.ReturnType; |
||||||
|
var args = string.Empty; |
||||||
|
|
||||||
|
if (arguments.Count > 0) |
||||||
|
args = VisitParameters(function.Parameters, hasNames: false); |
||||||
|
|
||||||
|
var callingConvention = string.Empty; |
||||||
|
if (function.CallingConvention != CallingConvention.Default && |
||||||
|
function.CallingConvention != CallingConvention.C) |
||||||
|
{ |
||||||
|
string conventionString = function.CallingConvention.ToString(); |
||||||
|
callingConvention = $"__{conventionString.ToLowerInvariant()} "; |
||||||
|
} |
||||||
|
return $"{returnType.Visit(this)} ({callingConvention}{{0}})({args})"; |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitParameters(IEnumerable<Parameter> @params, |
||||||
|
bool hasNames = true) |
||||||
|
{ |
||||||
|
var args = new List<string>(); |
||||||
|
|
||||||
|
foreach (var param in @params) |
||||||
|
args.Add(VisitParameter(param, hasNames)); |
||||||
|
|
||||||
|
if (PrintFlavorKind == CppTypePrintFlavorKind.ObjC) |
||||||
|
return string.Join(" ", args); |
||||||
|
|
||||||
|
return string.Join(", ", args); |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitParameter(Parameter param, |
||||||
|
bool hasName = true) |
||||||
|
{ |
||||||
|
Parameter oldParam = Parameter; |
||||||
|
Parameter = param; |
||||||
|
|
||||||
|
var result = param.Type.Visit(this, param.QualifiedType.Qualifiers); |
||||||
|
|
||||||
|
Parameter = oldParam; |
||||||
|
|
||||||
|
string name = param.Name; |
||||||
|
bool printName = hasName && !string.IsNullOrEmpty(name); |
||||||
|
|
||||||
|
if (PrintFlavorKind == CppTypePrintFlavorKind.ObjC) |
||||||
|
return printName ? $":({result.Type}){name}" : $":({result.Type})"; |
||||||
|
|
||||||
|
if (!printName) |
||||||
|
return result; |
||||||
|
|
||||||
|
result.Name = param.Name; |
||||||
|
return result.ToString(); |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitDelegate(FunctionType function) |
||||||
|
{ |
||||||
|
throw new NotImplementedException(); |
||||||
|
} |
||||||
|
|
||||||
|
public TypePrinterResult GetDeclName(Declaration declaration, |
||||||
|
TypePrintScopeKind scope) |
||||||
|
{ |
||||||
|
switch (scope) |
||||||
|
{ |
||||||
|
case TypePrintScopeKind.Local: |
||||||
|
{ |
||||||
|
if (ContextKind == TypePrinterContextKind.Managed) |
||||||
|
{ |
||||||
|
return PrintLogicalNames ? declaration.LogicalName : declaration.Name; |
||||||
|
} |
||||||
|
|
||||||
|
return PrintLogicalNames ? declaration.LogicalOriginalName |
||||||
|
: declaration.OriginalName; |
||||||
|
} |
||||||
|
case TypePrintScopeKind.Qualified: |
||||||
|
{ |
||||||
|
if (ContextKind == TypePrinterContextKind.Managed) |
||||||
|
{ |
||||||
|
var outputNamespace = declaration.TranslationUnit?.Module?.OutputNamespace; |
||||||
|
if (!string.IsNullOrEmpty(outputNamespace)) |
||||||
|
return $"{outputNamespace}::{declaration.QualifiedName}"; |
||||||
|
|
||||||
|
return declaration.QualifiedName; |
||||||
|
} |
||||||
|
|
||||||
|
if (declaration.Namespace is Class) |
||||||
|
return $"{declaration.Namespace.Visit(this)}::{declaration.OriginalName}"; |
||||||
|
|
||||||
|
return PrintLogicalNames ? declaration.QualifiedLogicalOriginalName |
||||||
|
: declaration.QualifiedOriginalName; |
||||||
|
} |
||||||
|
case TypePrintScopeKind.GlobalQualified: |
||||||
|
{ |
||||||
|
var name = (ContextKind == TypePrinterContextKind.Managed) ? |
||||||
|
declaration.Name : declaration.OriginalName; |
||||||
|
|
||||||
|
if (declaration.Namespace is Class) |
||||||
|
return $"{declaration.Namespace.Visit(this)}::{name}"; |
||||||
|
|
||||||
|
var qualifier = PrintFlavorKind == CppTypePrintFlavorKind.Cpp ? "::" : string.Empty; |
||||||
|
return qualifier + GetDeclName(declaration, TypePrintScopeKind.Qualified); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
throw new NotSupportedException(); |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitDeclaration(Declaration decl) |
||||||
|
{ |
||||||
|
return GetDeclName(decl, ScopeKind); |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitTranslationUnit(TranslationUnit unit) |
||||||
|
{ |
||||||
|
return VisitDeclaration(unit); |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitClassDecl(Class @class) |
||||||
|
{ |
||||||
|
if (@class.CompleteDeclaration != null) |
||||||
|
return VisitClassDecl(@class.CompleteDeclaration as Class); |
||||||
|
|
||||||
|
return VisitDeclaration(@class); |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitClassTemplateSpecializationDecl( |
||||||
|
ClassTemplateSpecialization specialization) |
||||||
|
{ |
||||||
|
return string.Format("{0}<{1}>", specialization.TemplatedDecl.Visit(this), |
||||||
|
string.Join(", ", |
||||||
|
specialization.Arguments.Where( |
||||||
|
a => a.Type.Type != null && |
||||||
|
!(a.Type.Type is DependentNameType)).Select(a => a.Type.Visit(this)))); |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitFieldDecl(Field field) |
||||||
|
{ |
||||||
|
return VisitDeclaration(field); |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitFunctionDecl(Function function) |
||||||
|
{ |
||||||
|
return VisitDeclaration(function); |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitMethodDecl(Method method) |
||||||
|
{ |
||||||
|
// HACK: this should never happen but there's an inexplicable crash
|
||||||
|
// with the 32-bit Windows CI - needs investigation.
|
||||||
|
var functionType = method.FunctionType.Type.Desugar() as FunctionType; |
||||||
|
if (functionType == null) |
||||||
|
return string.Empty; |
||||||
|
var returnType = method.IsConstructor || method.IsDestructor || |
||||||
|
method.OperatorKind == CXXOperatorKind.Conversion || |
||||||
|
method.OperatorKind == CXXOperatorKind.ExplicitConversion ? |
||||||
|
string.Empty : $"{method.OriginalReturnType.Visit(this)} "; |
||||||
|
var @class = method.Namespace.Visit(this); |
||||||
|
var @params = string.Join(", ", method.Parameters.Select(p => p.Visit(this))); |
||||||
|
var @const = (method.IsConst ? " const" : string.Empty); |
||||||
|
var name = method.OperatorKind == CXXOperatorKind.Conversion || |
||||||
|
method.OperatorKind == CXXOperatorKind.ExplicitConversion ? |
||||||
|
$"operator {method.OriginalReturnType.Visit(this)}" : |
||||||
|
method.OriginalName; |
||||||
|
|
||||||
|
string exceptionType; |
||||||
|
switch (functionType.ExceptionSpecType) |
||||||
|
{ |
||||||
|
case ExceptionSpecType.BasicNoexcept: |
||||||
|
exceptionType = " noexcept"; |
||||||
|
break; |
||||||
|
case ExceptionSpecType.NoexceptFalse: |
||||||
|
exceptionType = " noexcept(false)"; |
||||||
|
break; |
||||||
|
case ExceptionSpecType.NoexceptTrue: |
||||||
|
exceptionType = " noexcept(true)"; |
||||||
|
break; |
||||||
|
// TODO: research and handle the remaining cases
|
||||||
|
default: |
||||||
|
exceptionType = string.Empty; |
||||||
|
break; |
||||||
|
} |
||||||
|
return $"{returnType}{@class}::{name}({@params}){@const}{exceptionType}"; |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitParameterDecl(Parameter parameter) |
||||||
|
{ |
||||||
|
return VisitParameter(parameter, hasName: false); |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitTypedefDecl(TypedefDecl typedef) |
||||||
|
{ |
||||||
|
if (ResolveTypedefs) |
||||||
|
return typedef.Type.Visit(this); |
||||||
|
|
||||||
|
if (PrintFlavorKind != CppTypePrintFlavorKind.Cpp) |
||||||
|
return typedef.OriginalName; |
||||||
|
|
||||||
|
if (ContextKind == TypePrinterContextKind.Native) |
||||||
|
return GetDeclName(typedef, ScopeKind); |
||||||
|
|
||||||
|
/*string name; |
||||||
|
if (typedef.Type.Desugar().IsPrimitiveType()) |
||||||
|
{ |
||||||
|
PushContext(TypePrinterContextKind.Native); |
||||||
|
name = GetDeclName(typedef, ScopeKind); |
||||||
|
PopContext(); |
||||||
|
|
||||||
|
return name; |
||||||
|
}*/ |
||||||
|
|
||||||
|
var result = typedef.Type.Visit(this); |
||||||
|
|
||||||
|
return result; |
||||||
|
|
||||||
|
//name = GetDeclName(typedef, ScopeKind);
|
||||||
|
//return name;
|
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitTypeAliasDecl(TypeAlias typeAlias) |
||||||
|
{ |
||||||
|
return VisitDeclaration(typeAlias); |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitEnumDecl(Enumeration @enum) |
||||||
|
{ |
||||||
|
return VisitDeclaration(@enum); |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitEnumItemDecl(Enumeration.Item item) |
||||||
|
{ |
||||||
|
return VisitDeclaration(item); |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitVariableDecl(Variable variable) |
||||||
|
{ |
||||||
|
return VisitDeclaration(variable); |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitClassTemplateDecl(ClassTemplate template) |
||||||
|
{ |
||||||
|
return VisitDeclaration(template); |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitFunctionTemplateDecl(FunctionTemplate template) |
||||||
|
{ |
||||||
|
return VisitDeclaration(template); |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitMacroDefinition(MacroDefinition macro) |
||||||
|
{ |
||||||
|
throw new NotImplementedException(); |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitNamespace(Namespace @namespace) |
||||||
|
{ |
||||||
|
return VisitDeclaration(@namespace); |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitEvent(Event @event) |
||||||
|
{ |
||||||
|
return string.Empty; |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitProperty(Property property) |
||||||
|
{ |
||||||
|
return VisitDeclaration(property); |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitFriend(Friend friend) |
||||||
|
{ |
||||||
|
throw new NotImplementedException(); |
||||||
|
} |
||||||
|
|
||||||
|
public override string ToString(CppSharp.AST.Type type) |
||||||
|
{ |
||||||
|
return type.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitTemplateTemplateParameterDecl( |
||||||
|
TemplateTemplateParameter templateTemplateParameter) |
||||||
|
{ |
||||||
|
return templateTemplateParameter.Name; |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitTemplateParameterDecl( |
||||||
|
TypeTemplateParameter templateParameter) |
||||||
|
{ |
||||||
|
if (templateParameter.DefaultArgument.Type == null) |
||||||
|
return templateParameter.Name; |
||||||
|
|
||||||
|
return $"{templateParameter.Name} = {templateParameter.DefaultArgument.Visit(this)}"; |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitNonTypeTemplateParameterDecl( |
||||||
|
NonTypeTemplateParameter nonTypeTemplateParameter) |
||||||
|
{ |
||||||
|
if (nonTypeTemplateParameter.DefaultArgument == null) |
||||||
|
return nonTypeTemplateParameter.Name; |
||||||
|
|
||||||
|
return $"{nonTypeTemplateParameter.Name} = {nonTypeTemplateParameter.DefaultArgument.String}"; |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitTypedefNameDecl(TypedefNameDecl typedef) |
||||||
|
{ |
||||||
|
return VisitDeclaration(typedef); |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitTypeAliasTemplateDecl(TypeAliasTemplate typeAliasTemplate) |
||||||
|
{ |
||||||
|
return VisitDeclaration(typeAliasTemplate); |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitFunctionTemplateSpecializationDecl( |
||||||
|
FunctionTemplateSpecialization specialization) |
||||||
|
{ |
||||||
|
throw new NotImplementedException(); |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitVarTemplateDecl(VarTemplate template) |
||||||
|
{ |
||||||
|
return VisitDeclaration(template); |
||||||
|
} |
||||||
|
|
||||||
|
public override TypePrinterResult VisitVarTemplateSpecializationDecl( |
||||||
|
VarTemplateSpecialization template) |
||||||
|
{ |
||||||
|
return VisitDeclaration(template); |
||||||
|
} |
||||||
|
|
||||||
|
private string GetStringQuals(TypeQualifiers quals, bool appendSpace = true) |
||||||
|
{ |
||||||
|
var stringQuals = new List<string>(); |
||||||
|
if (PrintTypeQualifiers) |
||||||
|
{ |
||||||
|
if (quals.IsConst) |
||||||
|
stringQuals.Add("const"); |
||||||
|
if (quals.IsVolatile) |
||||||
|
stringQuals.Add("volatile"); |
||||||
|
} |
||||||
|
if (stringQuals.Count == 0) |
||||||
|
return string.Empty; |
||||||
|
return string.Join(" ", stringQuals) + (appendSpace ? " " : string.Empty); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,52 @@ |
|||||||
|
using System; |
||||||
|
using CppSharp.AST; |
||||||
|
using CppSharp.Generators; |
||||||
|
using CppSharp.Generators.C; |
||||||
|
using Attribute = System.Attribute; |
||||||
|
|
||||||
|
namespace CppSharp.Types |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Declaration maps allow customization of generated code, either
|
||||||
|
/// partially or fully, depending on how its setup.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class DeclMap |
||||||
|
{ |
||||||
|
public BindingContext Context { get; set; } |
||||||
|
public IDeclMapDatabase DeclMapDatabase { get; set; } |
||||||
|
|
||||||
|
public bool IsEnabled { get; set; } = true; |
||||||
|
|
||||||
|
public virtual bool IsIgnored => false; |
||||||
|
|
||||||
|
public Declaration Declaration { get; set; } |
||||||
|
public DeclarationContext DeclarationContext { get; set; } |
||||||
|
|
||||||
|
public abstract Declaration GetDeclaration(); |
||||||
|
|
||||||
|
public virtual void Generate(CCodeGenerator generator) |
||||||
|
{ |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] |
||||||
|
public class DeclMapAttribute : Attribute |
||||||
|
{ |
||||||
|
public GeneratorKind GeneratorKind { get; set; } |
||||||
|
|
||||||
|
public DeclMapAttribute() : this(0) |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
public DeclMapAttribute(GeneratorKind generatorKind) |
||||||
|
{ |
||||||
|
GeneratorKind = generatorKind; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public interface IDeclMapDatabase |
||||||
|
{ |
||||||
|
bool FindDeclMap(Declaration declaration, out DeclMap declMap); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,85 @@ |
|||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Linq; |
||||||
|
using CppSharp.AST; |
||||||
|
using CppSharp.Generators; |
||||||
|
|
||||||
|
namespace CppSharp.Types |
||||||
|
{ |
||||||
|
public class DeclMapDatabase : IDeclMapDatabase |
||||||
|
{ |
||||||
|
public IDictionary<Declaration, DeclMap> DeclMaps { get; set; } |
||||||
|
|
||||||
|
public DeclMapDatabase(BindingContext bindingContext) |
||||||
|
{ |
||||||
|
DeclMaps = new Dictionary<Declaration, DeclMap>(); |
||||||
|
SetupDeclMaps(bindingContext); |
||||||
|
} |
||||||
|
|
||||||
|
private void SetupDeclMaps(BindingContext bindingContext) |
||||||
|
{ |
||||||
|
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) |
||||||
|
{ |
||||||
|
try |
||||||
|
{ |
||||||
|
var types = assembly.FindDerivedTypes(typeof(DeclMap)); |
||||||
|
SetupDeclMaps(types, bindingContext); |
||||||
|
} |
||||||
|
catch (System.Reflection.ReflectionTypeLoadException ex) |
||||||
|
{ |
||||||
|
Diagnostics.Error("Error loading decl maps from assembly '{0}': {1}", |
||||||
|
assembly.GetName().Name, ex.Message); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void SetupDeclMaps(IEnumerable<System.Type> types, |
||||||
|
BindingContext bindingContext) |
||||||
|
{ |
||||||
|
foreach (var type in types) |
||||||
|
{ |
||||||
|
var attrs = type.GetCustomAttributes(typeof(DeclMapAttribute), true); |
||||||
|
foreach (DeclMapAttribute attr in attrs) |
||||||
|
{ |
||||||
|
if (attr.GeneratorKind == 0 || |
||||||
|
attr.GeneratorKind == bindingContext.Options.GeneratorKind) |
||||||
|
{ |
||||||
|
var declMap = (DeclMap) Activator.CreateInstance(type); |
||||||
|
declMap.Context = bindingContext; |
||||||
|
declMap.DeclMapDatabase = this; |
||||||
|
|
||||||
|
var decl = declMap.GetDeclaration(); |
||||||
|
if (decl == null) |
||||||
|
continue; |
||||||
|
|
||||||
|
DeclMaps[decl] = declMap; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public bool FindDeclMap(Declaration decl, out DeclMap declMap) |
||||||
|
{ |
||||||
|
// Looks up the decl in the cache map.
|
||||||
|
if (declMaps.ContainsKey(decl)) |
||||||
|
{ |
||||||
|
declMap = declMaps[decl]; |
||||||
|
return declMap.IsEnabled; |
||||||
|
} |
||||||
|
|
||||||
|
var foundDecl = DeclMaps.Keys.FirstOrDefault(d => d.OriginalPtr == decl.OriginalPtr); |
||||||
|
if (foundDecl != null) |
||||||
|
{ |
||||||
|
declMap = DeclMaps[foundDecl]; |
||||||
|
declMaps[decl] = declMap; |
||||||
|
return declMap.IsEnabled; |
||||||
|
} |
||||||
|
|
||||||
|
declMap = null; |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
private readonly Dictionary<Declaration, DeclMap> declMaps = |
||||||
|
new Dictionary<Declaration, DeclMap>(); |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue