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