Browse Source

WIP changes.

wip
João Matos 5 years ago
parent
commit
b5d7c8149e
  1. 3
      build/Tests.lua
  2. 2
      src/AST/ClassExtensions.cs
  3. 8
      src/AST/Declaration.cs
  4. 11
      src/AST/Method.cs
  5. 2
      src/CppParser/Parser.cpp
  6. 57
      src/CppParser/ParserGen/ParserGen.cs
  7. 12
      src/Generator.Tests/AST/TestAST.cs
  8. 2
      src/Generator/BindingContext.cs
  9. 9
      src/Generator/Driver.cs
  10. 98
      src/Generator/Generator.cs
  11. 21
      src/Generator/Generators/C/CCodeGenerator.cs
  12. 40
      src/Generator/Generators/C/CGenerator.cs
  13. 4
      src/Generator/Generators/C/CppGenerator.cs
  14. 25
      src/Generator/Generators/C/CppHeaders.cs
  15. 23
      src/Generator/Generators/C/CppMarshal.cs
  16. 89
      src/Generator/Generators/C/CppSources.cs
  17. 59
      src/Generator/Generators/C/CppTypePrinter.cs
  18. 35
      src/Generator/Generators/C/NAPI/NAPIGenerator.cs
  19. 23
      src/Generator/Generators/C/NAPI/NAPIHeaders.cs
  20. 37
      src/Generator/Generators/C/NAPI/NAPIModule.cs
  21. 3
      src/Generator/Generators/CLI/CLIHeaders.cs
  22. 1
      src/Generator/Generators/CLI/CLITypeReferences.cs
  23. 17
      src/Generator/Generators/CSharp/CSharpGenerator.cs
  24. 3
      src/Generator/Generators/CodeGenerator.cs
  25. 48
      src/Generator/Generators/JS/JSGenerator.cs
  26. 632
      src/Generator/Generators/JS/JSHeaders.cs
  27. 709
      src/Generator/Generators/JS/JSMarshal.cs
  28. 725
      src/Generator/Generators/JS/JSSources.cs
  29. 734
      src/Generator/Generators/JS/JSTypePrinter.cs
  30. 30
      src/Generator/Library.cs
  31. 10
      src/Generator/Options.cs
  32. 1
      src/Generator/Passes/CheckAmbiguousFunctions.cs
  33. 13
      src/Generator/Passes/CheckDuplicatedNamesPass.cs
  34. 27
      src/Generator/Passes/CheckIgnoredDecls.cs
  35. 3
      src/Generator/Passes/FieldToPropertyPass.cs
  36. 12
      src/Generator/Passes/RenamePass.cs
  37. 52
      src/Generator/Types/DeclMap.cs
  38. 85
      src/Generator/Types/DeclMapDatabase.cs
  39. 64
      src/Generator/Types/TypeMap.cs
  40. 7
      tests/Native/AST.h

3
build/Tests.lua

@ -195,6 +195,8 @@ function SetupTestProjectsCSharp(name, depends, extraFiles, suffix)
end end
function SetupTestProjectsCLI(name, extraFiles, suffix) function SetupTestProjectsCLI(name, extraFiles, suffix)
SetupTestGeneratorBuildEvent(name)
if (not os.ishost("windows")) or (_ACTION == "netcore") then if (not os.ishost("windows")) or (_ACTION == "netcore") then
return return
end end
@ -207,7 +209,6 @@ function SetupTestProjectsCLI(name, extraFiles, suffix)
clr "On" clr "On"
dependson { name .. ".Gen", name .. ".Native", "CppSharp.Generator" } dependson { name .. ".Gen", name .. ".Native", "CppSharp.Generator" }
SetupTestGeneratorBuildEvent(name)
if (suffix ~= nil) then if (suffix ~= nil) then
nm = name .. suffix nm = name .. suffix

2
src/AST/ClassExtensions.cs

@ -143,7 +143,7 @@ namespace CppSharp.AST
Class @base = null; Class @base = null;
if (@class.HasBaseClass) if (@class.HasBaseClass)
@base = @class.Bases[0].Class; @base = @class.BaseClass;
return @base?.IsRefType == true && @base.IsGenerated; return @base?.IsRefType == true && @base.IsGenerated;
} }

8
src/AST/Declaration.cs

@ -63,6 +63,9 @@ namespace CppSharp.AST
set set
{ {
//if (this is Declaration && (this as Declaration).Name == "TryBefore")
//System.Diagnostics.Debugger.Break();
generationKind = value; generationKind = value;
} }
} }
@ -72,6 +75,11 @@ namespace CppSharp.AST
/// </summary> /// </summary>
public virtual bool IsGenerated => GenerationKind == GenerationKind.Generate; public virtual bool IsGenerated => GenerationKind == GenerationKind.Generate;
/// <summary>
/// Whether the declaration has an explicit set generation kind.
/// </summary>
public bool HasExplicitGenerationKind => generationKind.HasValue;
/// <summary> /// <summary>
/// Whether the declaration was explicitly set to be generated via /// Whether the declaration was explicitly set to be generated via
/// the GenerationKind propery as opposed to the default generated state. /// the GenerationKind propery as opposed to the default generated state.

11
src/AST/Method.cs

@ -1,3 +1,4 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using CppSharp.AST.Extensions; using CppSharp.AST.Extensions;
@ -188,5 +189,15 @@ namespace CppSharp.AST
} }
private bool? isOverride; private bool? isOverride;
public bool HasSameSignature(Method other)
{
return Parameters.SequenceEqual(other.Parameters, ParameterTypeComparer.Instance);
}
public override string ToString()
{
return DebugText;
}
} }
} }

2
src/CppParser/Parser.cpp

@ -3007,7 +3007,7 @@ void Parser::CompleteIfSpecializationType(const clang::QualType& QualType)
if (TS != nullptr && TS->isIncomplete) if (TS != nullptr && TS->isIncomplete)
{ {
TS->isIncomplete = false; TS->isIncomplete = false;
WalkRecordCXX(CTS, TS); //WalkRecordCXX(CTS, TS);
} }
} }

57
src/CppParser/ParserGen/ParserGen.cs

@ -1,12 +1,8 @@
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using CppSharp.AST; using CppSharp.AST;
using CppSharp.Generators; using CppSharp.Generators;
using CppSharp.Parser; using CppSharp.Parser;
using CppSharp.Passes;
using CppAbi = CppSharp.Parser.AST.CppAbi;
namespace CppSharp namespace CppSharp
{ {
@ -19,6 +15,8 @@ namespace CppSharp
internal readonly string Triple; internal readonly string Triple;
internal readonly bool IsGnuCpp11Abi; internal readonly bool IsGnuCpp11Abi;
public static string IncludesDir => GetSourceDirectory("include");
public ParserGen(GeneratorKind kind, string triple, public ParserGen(GeneratorKind kind, string triple,
bool isGnuCpp11Abi = false) bool isGnuCpp11Abi = false)
{ {
@ -92,10 +90,32 @@ namespace CppSharp
{ {
options.MicrosoftMode = false; options.MicrosoftMode = false;
options.NoBuiltinIncludes = true; options.NoBuiltinIncludes = true;
options.NoStandardIncludes = true;
if (Platform.IsLinux)
{
options.SetupLinux();
}
else
{
/*
options.AddDefines("_ISOMAC");
options.AddSystemIncludeDirs($"{IncludesDir}/libcxx/include");
options.AddSystemIncludeDirs($"{IncludesDir}/libc/include/x86_64-linux-gnu");
options.AddSystemIncludeDirs($"{IncludesDir}/libc/include/x86_64-linux-any");
options.AddSystemIncludeDirs($"{IncludesDir}/libc/include/any-linux-any");
options.AddSystemIncludeDirs($"{IncludesDir}/libc/include/generic-glibc");
options.AddSystemIncludeDirs($"{IncludesDir}/libc/glibc/include");
options.AddSystemIncludeDirs($"{IncludesDir}/libc/glibc");
options.AddSystemIncludeDirs(options.BuiltinsDir);
//options.AddSystemIncludeDirs($"{IncludesDir}/include");
options.AddArguments("-fgnuc-version=6.0.0");
options.AddArguments("-stdlib=libc++");*/
options.SetupLinux($"{IncludesDir}/linux");
}
var headersPath = Platform.IsLinux ? string.Empty :
Path.Combine(GetSourceDirectory("build"), "headers", "x86_64-linux-gnu");
options.SetupLinux(headersPath);
options.AddDefines("_GLIBCXX_USE_CXX11_ABI=" + (IsGnuCpp11Abi ? "1" : "0")); options.AddDefines("_GLIBCXX_USE_CXX11_ABI=" + (IsGnuCpp11Abi ? "1" : "0"));
} }
@ -103,8 +123,8 @@ namespace CppSharp
{ {
if (Platform.IsMacOS) if (Platform.IsMacOS)
{ {
options.SetupXcode(); //options.SetupXcode();
return; //return;
} }
options.MicrosoftMode = false; options.MicrosoftMode = false;
@ -113,10 +133,13 @@ namespace CppSharp
var headersPath = Path.Combine(GetSourceDirectory("build"), "headers", var headersPath = Path.Combine(GetSourceDirectory("build"), "headers",
"osx"); "osx");
options.AddSystemIncludeDirs(Path.Combine(headersPath, "libcxx", "include")); //IncludesDir
options.AddSystemIncludeDirs(Path.Combine(headersPath, "include", "c++", "v1"));
options.AddSystemIncludeDirs(options.BuiltinsDir); options.AddSystemIncludeDirs(options.BuiltinsDir);
options.AddSystemIncludeDirs(Path.Combine(headersPath, "include")); options.AddSystemIncludeDirs(Path.Combine(headersPath, "include"));
options.AddArguments("-stdlib=libc++"); options.AddArguments("-stdlib=libc++");
options.Verbose = true;
} }
public void SetupPasses(Driver driver) public void SetupPasses(Driver driver)
@ -153,6 +176,10 @@ namespace CppSharp
public static void Main(string[] args) public static void Main(string[] args)
{ {
var useCrossHeaders = true;
var osxHeadersPath = Path.Combine(GetSourceDirectory("build"), @"headers\osx");
var linuxHeadersPath = Path.Combine(GetSourceDirectory("build"), @"headers\x86_64-linux-gnu");
if (Platform.IsWindows) if (Platform.IsWindows)
{ {
Console.WriteLine("Generating the C++/CLI parser bindings for Windows..."); Console.WriteLine("Generating the C++/CLI parser bindings for Windows...");
@ -168,20 +195,18 @@ namespace CppSharp
Console.WriteLine(); Console.WriteLine();
} }
var osxHeadersPath = Path.Combine(GetSourceDirectory("build"), @"headers\osx"); if (Platform.IsMacOS || useCrossHeaders)
if (Directory.Exists(osxHeadersPath) || Platform.IsMacOS)
{ {
Console.WriteLine("Generating the C# parser bindings for OSX..."); Console.WriteLine("Generating the C# parser bindings for OSX...");
ConsoleDriver.Run(new ParserGen(GeneratorKind.CSharp, "i686-apple-darwin12.4.0")); ConsoleDriver.Run(new ParserGen(GeneratorKind.CSharp, "i686-apple-darwin"));
Console.WriteLine(); Console.WriteLine();
Console.WriteLine("Generating the C# parser bindings for OSX..."); Console.WriteLine("Generating the C# parser bindings for OSX...");
ConsoleDriver.Run(new ParserGen(GeneratorKind.CSharp, "x86_64-apple-darwin12.4.0")); ConsoleDriver.Run(new ParserGen(GeneratorKind.CSharp, "x86_64-apple-darwin"));
Console.WriteLine(); Console.WriteLine();
} }
var linuxHeadersPath = Path.Combine(GetSourceDirectory("build"), @"headers\x86_64-linux-gnu"); if (Platform.IsLinux)
if (Directory.Exists(linuxHeadersPath) || Platform.IsLinux)
{ {
Console.WriteLine("Generating the C# parser bindings for Linux..."); Console.WriteLine("Generating the C# parser bindings for Linux...");
ConsoleDriver.Run(new ParserGen(GeneratorKind.CSharp, "x86_64-linux-gnu")); ConsoleDriver.Run(new ParserGen(GeneratorKind.CSharp, "x86_64-linux-gnu"));

12
src/Generator.Tests/AST/TestAST.cs

@ -499,6 +499,18 @@ namespace CppSharp.Generator.Tests.AST
Assert.That(type, Is.EqualTo("const char* const")); Assert.That(type, Is.EqualTo("const char* const"));
} }
[Test]
public void TestPrintingConstPointerTypedef()
{
var cppTypePrinter = new CppTypePrinter(Context) { ScopeKind = TypePrintScopeKind.Qualified };
cppTypePrinter.PushContext(TypePrinterContextKind.Native);
var method = Context.ASTContext.FindCompleteClass("TestTypePrinting").FindMethod("ConstPointerTypedef");
var result = method.Parameters[0].Visit(cppTypePrinter);
var type = result.ToString();
Assert.That(type, Is.EqualTo("const MyChar*"));
}
[Test] [Test]
public void TestPrintingSpecializationWithConstValue() public void TestPrintingSpecializationWithConstValue()
{ {

2
src/Generator/BindingContext.cs

@ -14,7 +14,9 @@ namespace CppSharp.Generators
public ParserTargetInfo TargetInfo { get; set; } public ParserTargetInfo TargetInfo { get; set; }
public SymbolContext Symbols { get; } public SymbolContext Symbols { get; }
public TypeMapDatabase TypeMaps { get; set; } public TypeMapDatabase TypeMaps { get; set; }
public DeclMapDatabase DeclMaps { get; set; }
public PassBuilder<TranslationUnitPass> TranslationUnitPasses { get; } public PassBuilder<TranslationUnitPass> TranslationUnitPasses { get; }
public PassBuilder<GeneratorOutputPass> GeneratorOutputPasses { get; } public PassBuilder<GeneratorOutputPass> GeneratorOutputPasses { get; }

9
src/Generator/Driver.cs

@ -14,6 +14,7 @@ using CppSharp.Utils;
using Microsoft.CSharp; using Microsoft.CSharp;
using CppSharp.Types; using CppSharp.Types;
using CppSharp.Generators.Cpp; using CppSharp.Generators.Cpp;
using CppSharp.Generators.C;
namespace CppSharp namespace CppSharp
{ {
@ -36,12 +37,16 @@ namespace CppSharp
{ {
switch (kind) switch (kind)
{ {
case GeneratorKind.C:
return new CGenerator(Context);
case GeneratorKind.CPlusPlus: case GeneratorKind.CPlusPlus:
return new CppGenerator(Context); return new CppGenerator(Context);
case GeneratorKind.CLI: case GeneratorKind.CLI:
return new CLIGenerator(Context); return new CLIGenerator(Context);
case GeneratorKind.CSharp: case GeneratorKind.CSharp:
return new CSharpGenerator(Context); return new CSharpGenerator(Context);
case GeneratorKind.NAPI:
return new NAPIGenerator(Context);
} }
throw new NotImplementedException(); throw new NotImplementedException();
@ -77,6 +82,9 @@ namespace CppSharp
public void SetupTypeMaps() => public void SetupTypeMaps() =>
Context.TypeMaps = new TypeMapDatabase(Context); Context.TypeMaps = new TypeMapDatabase(Context);
public void SetupDeclMaps() =>
Context.DeclMaps = new DeclMapDatabase(Context);
void OnSourceFileParsed(IEnumerable<string> files, ParserResult result) void OnSourceFileParsed(IEnumerable<string> files, ParserResult result)
{ {
OnFileParsed(files, result); OnFileParsed(files, result);
@ -458,6 +466,7 @@ namespace CppSharp
driver.SetupPasses(library); driver.SetupPasses(library);
driver.SetupTypeMaps(); driver.SetupTypeMaps();
driver.SetupDeclMaps();
library.Preprocess(driver, driver.Context.ASTContext); library.Preprocess(driver, driver.Context.ASTContext);

98
src/Generator/Generator.cs

@ -16,13 +16,14 @@ namespace CppSharp.Generators
CPlusPlus, CPlusPlus,
ObjectiveC, ObjectiveC,
Java, Java,
Swift Swift,
NAPI
} }
/// <summary> /// <summary>
/// Output generated by each backend generator. /// Output generated by each backend generator.
/// </summary> /// </summary>
public struct GeneratorOutput public class GeneratorOutput
{ {
/// <summary> /// <summary>
/// Translation unit associated with output. /// Translation unit associated with output.
@ -66,6 +67,12 @@ namespace CppSharp.Generators
} }
/// <summary>
/// Generates the outputs for the given translation units.
/// </summary>
/// <param name="units">The units to generate outputs for.</param>
public abstract List<CodeGenerator> Generate(IEnumerable<TranslationUnit> units);
/// <summary> /// <summary>
/// Generates the outputs. /// Generates the outputs.
/// </summary> /// </summary>
@ -73,73 +80,72 @@ namespace CppSharp.Generators
{ {
var outputs = new List<GeneratorOutput>(); var outputs = new List<GeneratorOutput>();
var units = Context.ASTContext.TranslationUnits.GetGenerated().ToList(); if (Context.Options.GenerationOutputMode == GenerationOutputMode.FilePerModule ||
if (Context.Options.IsCSharpGenerator &&
Context.Options.GenerateSingleCSharpFile) Context.Options.GenerateSingleCSharpFile)
{ {
foreach (var module in Context.Options.Modules) foreach (var module in Context.Options.Modules)
outputs.Add(GenerateModuleTemplate(module)); {
var output = GenerateModule(module);
if (output != null)
{
OnUnitGenerated(output);
outputs.Add(output);
}
}
} }
else else
{ {
GenerateTemplates(outputs, units.Where(u => !u.IsSystemHeader)); var units = Context.ASTContext.TranslationUnits.GetGenerated()
.Where(u => !u.IsSystemHeader).ToList();
if (Context.Options.IsCSharpGenerator && Context.Options.SystemModule != null) foreach (var unit in units)
outputs.Add(GenerateModuleTemplate(Context.Options.SystemModule)); {
var output = GenerateUnit(unit);
if (output != null)
{
outputs.Add(output);
OnUnitGenerated(output);
}
}
if (Context.Options.SystemModule != null)
{
var output = GenerateModule(Context.Options.SystemModule);
if (output != null)
{
OnUnitGenerated(output);
outputs.Add(output);
}
}
} }
return outputs; return outputs;
} }
private void GenerateTemplates(List<GeneratorOutput> outputs, IEnumerable<TranslationUnit> units) public virtual GeneratorOutput GenerateUnit(TranslationUnit unit)
{ {
foreach (var unit in units) var codeGenerators = Generate(new[] { unit });
{ if (codeGenerators.Count == 0)
var templates = Generate(new[] { unit }); return null;
if (templates.Count == 0)
return;
foreach (var template in templates) foreach (var codeGen in codeGenerators)
{ {
template.Process(); codeGen.Process();
}
var output = new GeneratorOutput
{
TranslationUnit = unit,
Outputs = templates
};
outputs.Add(output);
OnUnitGenerated(output);
} }
}
private GeneratorOutput GenerateModuleTemplate(Module module)
{
var output = new GeneratorOutput var output = new GeneratorOutput
{ {
TranslationUnit = new TranslationUnit TranslationUnit = unit,
{ Outputs = codeGenerators
FilePath = $"{module.LibraryName}.cs",
Module = module
},
Outputs = Generate(module.Units.GetGenerated())
}; };
output.Outputs[0].Process();
OnUnitGenerated(output);
return output; return output;
} }
/// <summary> public virtual GeneratorOutput GenerateModule(Module module)
/// Generates the outputs for the given translation units. {
/// </summary> throw new NotImplementedException();
/// <param name="units">The units to generate outputs for.</param> }
public abstract List<CodeGenerator> Generate(IEnumerable<TranslationUnit> units);
protected abstract string TypePrinterDelegate(CppSharp.AST.Type type); protected abstract string TypePrinterDelegate(CppSharp.AST.Type type);

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

@ -1,4 +1,5 @@
using CppSharp.AST; using CppSharp.AST;
using CppSharp.AST.Extensions;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -35,9 +36,12 @@ namespace CppSharp.Generators.C
typePrinter = new CppTypePrinter(context); typePrinter = new CppTypePrinter(context);
} }
public abstract override string FileExtension { get; } public override string FileExtension { get; } = "h";
public abstract override void Process(); public override void Process()
{
}
public ISet<CInclude> Includes = new HashSet<CInclude>(); public ISet<CInclude> Includes = new HashSet<CInclude>();
@ -369,8 +373,17 @@ namespace CppSharp.Generators.C
Write(")"); Write(")");
if (method.IsOverride && isDeclaration) if (method.IsConst)
Write(" override"); Write(" const");
if (isDeclaration)
{
if (method.IsOverride)
Write(" override");
//if (method.IsPure)
//Write(" = 0");
}
} }
public virtual void GenerateMethodParameters(Function function) public virtual void GenerateMethodParameters(Function function)

40
src/Generator/Generators/C/CGenerator.cs

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

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

@ -5,8 +5,8 @@ using CppSharp.Generators.C;
namespace CppSharp.Generators.Cpp namespace CppSharp.Generators.Cpp
{ {
/// <summary> /// <summary>
/// C/C++ generator responsible for driving the generation of source /// C++ generator responsible for driving the generation of source and
/// and header files. /// header files.
/// </summary> /// </summary>
public class CppGenerator : Generator public class CppGenerator : Generator
{ {

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

@ -16,6 +16,7 @@ namespace CppSharp.Generators.Cpp
public CppHeaders(BindingContext context, IEnumerable<TranslationUnit> units) public CppHeaders(BindingContext context, IEnumerable<TranslationUnit> units)
: base(context, units) : base(context, units)
{ {
CTypePrinter.PushContext(TypePrinterContextKind.Managed);
} }
public override string FileExtension => "h"; public override string FileExtension => "h";
@ -29,7 +30,10 @@ namespace CppSharp.Generators.Cpp
NewLine(); NewLine();
if (Options.OutputInteropIncludes) if (Options.OutputInteropIncludes)
{
WriteLine("#include \"CppSharp.h\""); WriteLine("#include \"CppSharp.h\"");
WriteLine("#include \"FastDelegates.h\"");
}
// Generate #include forward references. // Generate #include forward references.
PushBlock(BlockKind.IncludesForwardReferences); PushBlock(BlockKind.IncludesForwardReferences);
@ -163,7 +167,7 @@ namespace CppSharp.Generators.Cpp
} }
// Generate all the typedef declarations for the module. // Generate all the typedef declarations for the module.
GenerateTypedefs(decl); //GenerateTypedefs(decl);
// Generate all the struct/class declarations for the module. // Generate all the struct/class declarations for the module.
foreach (var @class in decl.Classes) foreach (var @class in decl.Classes)
@ -429,15 +433,30 @@ namespace CppSharp.Generators.Cpp
public void GenerateClassEvents(Class @class) public void GenerateClassEvents(Class @class)
{ {
Indent();
foreach (var @event in @class.Events) foreach (var @event in @class.Events)
{ {
if (!@event.IsGenerated) continue; if (!@event.IsGenerated) continue;
@event.Visit(this); @event.Visit(this);
} }
Unindent();
} }
public override bool VisitEvent(Event @event) 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; return true;
} }
@ -496,7 +515,7 @@ namespace CppSharp.Generators.Cpp
Write(" abstract sealed"); Write(" abstract sealed");
if (!@class.IsStatic && @class.HasRefBase()) if (!@class.IsStatic && @class.HasRefBase())
Write($" : public {QualifiedIdentifier(@class.Bases[0].Class)}"); Write($" : public {QualifiedIdentifier(@class.BaseClass)}");
} }
public void GenerateClassProperties(Class @class) public void GenerateClassProperties(Class @class)
@ -607,7 +626,7 @@ namespace CppSharp.Generators.Cpp
var desugared = type.Desugar(); var desugared = type.Desugar();
var finalType = (desugared.GetFinalPointee() ?? desugared).Desugar(); var finalType = (desugared.GetFinalPointee() ?? desugared).Desugar();
Class @class; Class @class;
return finalType.TryGetClass(out @class) && @class.IsIncomplete; return finalType.TryGetClass(out @class) && (@class.CompleteDeclaration == null && @class.IsIncomplete);
} }
} }
} }

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

@ -183,7 +183,12 @@ namespace CppSharp.Generators.Cpp
FunctionType function; FunctionType function;
if (decl.Type.IsPointerTo(out function)) if (decl.Type.IsPointerTo(out function))
{ {
throw new System.NotImplementedException(); 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); return decl.Type.Visit(this);
@ -256,7 +261,13 @@ namespace CppSharp.Generators.Cpp
public void WriteClassInstance(Class @class, string instance) public void WriteClassInstance(Class @class, string instance)
{ {
if (!Context.ReturnType.Type.IsPointer()) if (@class.CompleteDeclaration != null)
{
WriteClassInstance(@class.CompleteDeclaration as Class, instance);
return;
}
if (!Context.ReturnType.Type.Desugar().IsPointer())
{ {
Context.Return.Write($"{instance}"); Context.Return.Write($"{instance}");
return; return;
@ -302,6 +313,7 @@ namespace CppSharp.Generators.Cpp
public override bool VisitEnumDecl(Enumeration @enum) public override bool VisitEnumDecl(Enumeration @enum)
{ {
var typePrinter = new CppTypePrinter(Context.Context); var typePrinter = new CppTypePrinter(Context.Context);
typePrinter.PushContext(TypePrinterContextKind.Managed);
var typeName = typePrinter.VisitDeclaration(@enum); var typeName = typePrinter.VisitDeclaration(@enum);
Context.Return.Write($"({typeName}){Context.ReturnVarName}"); Context.Return.Write($"({typeName}){Context.ReturnVarName}");
@ -395,6 +407,7 @@ namespace CppSharp.Generators.Cpp
if (pointee is FunctionType) if (pointee is FunctionType)
{ {
var cppTypePrinter = new CppTypePrinter(Context.Context); var cppTypePrinter = new CppTypePrinter(Context.Context);
cppTypePrinter.PushContext(TypePrinterContextKind.Managed);
var cppTypeName = pointer.Visit(cppTypePrinter, quals); var cppTypeName = pointer.Visit(cppTypePrinter, quals);
return VisitDelegateType(cppTypeName); return VisitDelegateType(cppTypeName);
@ -488,10 +501,16 @@ namespace CppSharp.Generators.Cpp
if (decl.Type.IsPointerTo(out func)) if (decl.Type.IsPointerTo(out func))
{ {
var typePrinter = new CppTypePrinter(Context.Context); 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 // Use the original typedef name if available, otherwise just use the function pointer type
string cppTypeName; string cppTypeName;
if (!decl.IsSynthetized) if (!decl.IsSynthetized)
{
cppTypeName = "::" + typedef.Declaration.QualifiedOriginalName; cppTypeName = "::" + typedef.Declaration.QualifiedOriginalName;
}
else else
{ {
cppTypeName = decl.Type.Visit(typePrinter, quals); cppTypeName = decl.Type.Visit(typePrinter, quals);

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

@ -7,6 +7,7 @@ using CppSharp.AST;
using CppSharp.AST.Extensions; using CppSharp.AST.Extensions;
using CppSharp.Generators.C; using CppSharp.Generators.C;
using CppSharp.Generators.CLI; using CppSharp.Generators.CLI;
using CppSharp.Types;
namespace CppSharp.Generators.Cpp namespace CppSharp.Generators.Cpp
{ {
@ -18,6 +19,7 @@ namespace CppSharp.Generators.Cpp
public CppSources(BindingContext context, IEnumerable<TranslationUnit> units) public CppSources(BindingContext context, IEnumerable<TranslationUnit> units)
: base(context, units) : base(context, units)
{ {
CTypePrinter.PushContext(TypePrinterContextKind.Managed);
} }
public override string FileExtension { get { return "cpp"; } } public override string FileExtension { get { return "cpp"; } }
@ -116,6 +118,15 @@ namespace CppSharp.Generators.Cpp
public override bool VisitClassDecl(Class @class) 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); PushBlock(BlockKind.Class);
VisitDeclContext(@class); VisitDeclContext(@class);
@ -633,4 +644,82 @@ namespace CppSharp.Generators.Cpp
Write(string.Join(", ", names)); 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;
}
}
} }

59
src/Generator/Generators/C/CppTypePrinter.cs

@ -104,7 +104,7 @@ namespace CppSharp.Generators.C
var result = new TypePrinterResult var result = new TypePrinterResult
{ {
Type = array.Type.Visit(this), Type = array.QualifiedType.Visit(this),
NameSuffix = new System.Text.StringBuilder(arraySuffix) NameSuffix = new System.Text.StringBuilder(arraySuffix)
}; };
@ -232,18 +232,26 @@ namespace CppSharp.Generators.C
public override TypePrinterResult VisitTypedefType(TypedefType typedef, public override TypePrinterResult VisitTypedefType(TypedefType typedef,
TypeQualifiers quals) TypeQualifiers quals)
{ {
TypePrinterResult result;
FunctionType func; FunctionType func;
var qual = GetStringQuals(quals);
if (ResolveTypedefs && !typedef.Declaration.Type.IsPointerTo(out func)) if (ResolveTypedefs && !typedef.Declaration.Type.IsPointerTo(out func))
{ result = typedef.Declaration.QualifiedType.Visit(this);
TypePrinterResult type = typedef.Declaration.QualifiedType.Visit(this); else
return new TypePrinterResult { Type = $"{qual}{type.Type}", result = typedef.Declaration.Visit(this);
NamePrefix = type.NamePrefix, NameSuffix = type.NameSuffix };
}
var result = typedef.Declaration.Visit(this); var qual = GetStringQuals(quals);
if (result.NamePrefix.Length > 0)
result.NamePrefix.Append($"{qual}"); // 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; return result;
} }
@ -413,8 +421,13 @@ namespace CppSharp.Generators.C
public override TypePrinterResult VisitParameter(Parameter param, public override TypePrinterResult VisitParameter(Parameter param,
bool hasName = true) bool hasName = true)
{ {
Parameter oldParam = Parameter;
Parameter = param;
var result = param.Type.Visit(this, param.QualifiedType.Qualifiers); var result = param.Type.Visit(this, param.QualifiedType.Qualifiers);
Parameter = oldParam;
string name = param.Name; string name = param.Name;
bool printName = hasName && !string.IsNullOrEmpty(name); bool printName = hasName && !string.IsNullOrEmpty(name);
@ -493,6 +506,9 @@ namespace CppSharp.Generators.C
public override TypePrinterResult VisitClassDecl(Class @class) public override TypePrinterResult VisitClassDecl(Class @class)
{ {
if (@class.CompleteDeclaration != null)
return VisitClassDecl(@class.CompleteDeclaration as Class);
return VisitDeclaration(@class); return VisitDeclaration(@class);
} }
@ -568,10 +584,25 @@ namespace CppSharp.Generators.C
if (PrintFlavorKind != CppTypePrintFlavorKind.Cpp) if (PrintFlavorKind != CppTypePrintFlavorKind.Cpp)
return typedef.OriginalName; return typedef.OriginalName;
var originalNamespace = typedef.OriginalNamespace.Visit(this); if (ContextKind == TypePrinterContextKind.Native)
return string.IsNullOrEmpty(originalNamespace) || return GetDeclName(typedef, ScopeKind);
originalNamespace == "::" ?
typedef.OriginalName : $"{originalNamespace}::{typedef.OriginalName}"; /*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) public override TypePrinterResult VisitTypeAliasDecl(TypeAlias typeAlias)

35
src/Generator/Generators/C/NAPI/NAPIGenerator.cs

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

23
src/Generator/Generators/C/NAPI/NAPIHeaders.cs

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

37
src/Generator/Generators/C/NAPI/NAPIModule.cs

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

3
src/Generator/Generators/CLI/CLIHeaders.cs

@ -467,6 +467,7 @@ namespace CppSharp.Generators.CLI
if (!@event.IsGenerated) continue; if (!@event.IsGenerated) continue;
var cppTypePrinter = new CppTypePrinter(Context); var cppTypePrinter = new CppTypePrinter(Context);
cppTypePrinter.PushContext(TypePrinterContextKind.Native);
var cppArgs = cppTypePrinter.VisitParameters(@event.Parameters, hasNames: true); var cppArgs = cppTypePrinter.VisitParameters(@event.Parameters, hasNames: true);
WriteLine("private:"); WriteLine("private:");
@ -804,7 +805,7 @@ namespace CppSharp.Generators.CLI
var desugared = type.Desugar(); var desugared = type.Desugar();
var finalType = (desugared.GetFinalPointee() ?? desugared).Desugar(); var finalType = (desugared.GetFinalPointee() ?? desugared).Desugar();
Class @class; Class @class;
return finalType.TryGetClass(out @class) && @class.IsIncomplete; return finalType.TryGetClass(out @class) && (@class.CompleteDeclaration == null && @class.IsIncomplete); ;
} }
} }
} }

1
src/Generator/Generators/CLI/CLITypeReferences.cs

@ -1,5 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using CppSharp.AST; using CppSharp.AST;
using CppSharp.AST.Extensions; using CppSharp.AST.Extensions;
using CppSharp.Generators.AST; using CppSharp.Generators.AST;

17
src/Generator/Generators/CSharp/CSharpGenerator.cs

@ -23,6 +23,23 @@ namespace CppSharp.Generators.CSharp
return outputs; return outputs;
} }
public override GeneratorOutput GenerateModule(Module module)
{
var output = new GeneratorOutput
{
TranslationUnit = new TranslationUnit
{
FilePath = $"{module.LibraryName}.cs",
Module = module
},
Outputs = Generate(module.Units.GetGenerated())
};
output.Outputs[0].Process();
return output;
}
public override bool SetupPasses() public override bool SetupPasses()
{ {
if (Context.Options.GenerateDefaultValuesForArguments) if (Context.Options.GenerateDefaultValuesForArguments)

3
src/Generator/Generators/CodeGenerator.cs

@ -61,7 +61,8 @@ namespace CppSharp.Generators
protected CodeGenerator(BindingContext context, IEnumerable<TranslationUnit> units) protected CodeGenerator(BindingContext context, IEnumerable<TranslationUnit> units)
{ {
Context = context; Context = context;
TranslationUnits = new List<TranslationUnit>(units); if (units != null)
TranslationUnits = new List<TranslationUnit>(units);
} }
public abstract void Process(); public abstract void Process();

48
src/Generator/Generators/JS/JSGenerator.cs

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

632
src/Generator/Generators/JS/JSHeaders.cs

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

709
src/Generator/Generators/JS/JSMarshal.cs

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

725
src/Generator/Generators/JS/JSSources.cs

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

734
src/Generator/Generators/JS/JSTypePrinter.cs

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

30
src/Generator/Library.cs

@ -146,8 +146,8 @@ namespace CppSharp
{ {
var @enum = new Enumeration { Name = name }; var @enum = new Enumeration { Name = name };
var pattern = string.Join("|", macros); var regexPattern = string.Join("|", macros.Select(pattern => $"{pattern}$"));
var regex = new Regex(pattern); var regex = new Regex(regexPattern);
int maxItems = 0; int maxItems = 0;
TranslationUnit unitToAttach = null; TranslationUnit unitToAttach = null;
@ -186,13 +186,39 @@ namespace CppSharp
if (@enum.Items.Count > 0) if (@enum.Items.Count > 0)
{ {
@enum.BuiltinType = new BuiltinType(GetUnderlyingTypeForEnumValue(maxValue));
@enum.Type = @enum.BuiltinType;
@enum.Namespace = unitToAttach; @enum.Namespace = unitToAttach;
unitToAttach.Declarations.Add(@enum); unitToAttach.Declarations.Add(@enum);
} }
return @enum; return @enum;
} }
private static PrimitiveType GetUnderlyingTypeForEnumValue(ulong maxValue)
{
if (maxValue < (byte)sbyte.MaxValue)
return PrimitiveType.Char;
if (maxValue < byte.MaxValue)
return PrimitiveType.Char;
if (maxValue < (ushort)short.MaxValue)
return PrimitiveType.Short;
if (maxValue < ushort.MaxValue)
return PrimitiveType.UShort;
if (maxValue < int.MaxValue)
return PrimitiveType.Int;
if (maxValue < uint.MaxValue)
return PrimitiveType.UInt;
throw new NotImplementedException();
}
#endregion #endregion
#region Class Helpers #region Class Helpers

10
src/Generator/Options.cs

@ -8,6 +8,12 @@ using CppSharp.Generators;
namespace CppSharp namespace CppSharp
{ {
public enum GenerationOutputMode
{
FilePerModule,
FilePerUnit
}
public class DriverOptions public class DriverOptions
{ {
public DriverOptions() public DriverOptions()
@ -137,8 +143,12 @@ namespace CppSharp
/// <summary> /// <summary>
/// Generates a single C# file. /// Generates a single C# file.
/// </summary> /// </summary>
[Obsolete("Use the more general GenerationOutputMode property instead.")]
public bool GenerateSingleCSharpFile { get; set; } = true; public bool GenerateSingleCSharpFile { get; set; } = true;
public GenerationOutputMode GenerationOutputMode { get; set; } =
GenerationOutputMode.FilePerUnit;
/// <summary> /// <summary>
/// Generates default values of arguments in the C# code. /// Generates default values of arguments in the C# code.
/// </summary> /// </summary>

1
src/Generator/Passes/CheckAmbiguousFunctions.cs

@ -87,6 +87,7 @@ namespace CppSharp.Passes
if (!funcType.Equals(functionParams[i].Type.Desugar())) if (!funcType.Equals(functionParams[i].Type.Desugar()))
functionMappedParams++; functionMappedParams++;
if (!overloadType.Equals(overloadParams[i].Type.Desugar())) if (!overloadType.Equals(overloadParams[i].Type.Desugar()))
overloadMappedParams++; overloadMappedParams++;

13
src/Generator/Passes/CheckDuplicatedNamesPass.cs

@ -4,6 +4,7 @@ using System.Linq;
using CppSharp.AST; using CppSharp.AST;
using CppSharp.AST.Extensions; using CppSharp.AST.Extensions;
using CppSharp.Generators; using CppSharp.Generators;
using CppSharp.Generators.C;
using CppSharp.Generators.CLI; using CppSharp.Generators.CLI;
using CppSharp.Generators.CSharp; using CppSharp.Generators.CSharp;
using CppSharp.Types; using CppSharp.Types;
@ -201,12 +202,24 @@ namespace CppSharp.Passes
TypePrinter typePrinter = null; TypePrinter typePrinter = null;
switch (Options.GeneratorKind) switch (Options.GeneratorKind)
{ {
case GeneratorKind.C:
typePrinter = new CppTypePrinter(Context)
{
PrintFlavorKind = CppTypePrintFlavorKind.C
};
break;
case GeneratorKind.CPlusPlus:
case GeneratorKind.NAPI:
typePrinter = new CppTypePrinter(Context);
break;
case GeneratorKind.CLI: case GeneratorKind.CLI:
typePrinter = new CLITypePrinter(Context); typePrinter = new CLITypePrinter(Context);
break; break;
case GeneratorKind.CSharp: case GeneratorKind.CSharp:
typePrinter = new CSharpTypePrinter(Context); typePrinter = new CSharpTypePrinter(Context);
break; break;
default:
throw new System.NotImplementedException();
} }
DeclarationName.ParameterTypeComparer.TypePrinter = typePrinter; DeclarationName.ParameterTypeComparer.TypePrinter = typePrinter;
DeclarationName.ParameterTypeComparer.TypeMaps = Context.TypeMaps; DeclarationName.ParameterTypeComparer.TypeMaps = Context.TypeMaps;

27
src/Generator/Passes/CheckIgnoredDecls.cs

@ -13,9 +13,6 @@ namespace CppSharp.Passes
public bool CheckDeclarationAccess(Declaration decl) public bool CheckDeclarationAccess(Declaration decl)
{ {
if (decl.IsExplicitlyGenerated)
return true;
switch (decl.Access) switch (decl.Access)
{ {
case AccessSpecifier.Public: case AccessSpecifier.Public:
@ -79,6 +76,9 @@ namespace CppSharp.Passes
if (AlreadyVisited(decl)) if (AlreadyVisited(decl))
return false; return false;
if (decl.HasExplicitGenerationKind)
return true;
if (decl.GenerationKind == GenerationKind.None) if (decl.GenerationKind == GenerationKind.None)
return true; return true;
@ -292,8 +292,9 @@ namespace CppSharp.Passes
"Virtual method '{0}' was ignored due to ignored base '{1}'", "Virtual method '{0}' was ignored due to ignored base '{1}'",
method.QualifiedOriginalName, ignoredBase.Name); method.QualifiedOriginalName, ignoredBase.Name);
method.ExplicitlyIgnore(); //method.ExplicitlyIgnore();
return false; //return false;
return true;
} }
static bool HasIgnoredBaseClass(INamedDecl @override, Class @class, static bool HasIgnoredBaseClass(INamedDecl @override, Class @class,
@ -541,11 +542,19 @@ namespace CppSharp.Passes
Declaration decl; Declaration decl;
if (!finalType.TryGetDeclaration(out decl)) return true; if (!finalType.TryGetDeclaration(out decl)) return true;
var isCompleteDecl = !decl.IsIncomplete || decl.CompleteDeclaration != null;
var @class = (decl as Class); var @class = (decl as Class);
if (@class != null && @class.IsOpaque && !@class.IsDependent && if (@class != null && @class.IsOpaque)
!(@class is ClassTemplateSpecialization)) {
return true; var isPointerType = type.Desugar().IsPointer();
return !decl.IsIncomplete || decl.CompleteDeclaration != null; if (!isPointerType)
return isCompleteDecl;
if (!@class.IsDependent && !(@class is ClassTemplateSpecialization))
return true;
}
return isCompleteDecl;
} }
private bool IsTypeIgnored(Type type) private bool IsTypeIgnored(Type type)

3
src/Generator/Passes/FieldToPropertyPass.cs

@ -66,7 +66,8 @@ namespace CppSharp.Passes
AssociatedDeclaration = field AssociatedDeclaration = field
}; };
if (Options.GeneratorKind == GeneratorKind.CPlusPlus) if (Options.GeneratorKind == GeneratorKind.C ||
Options.GeneratorKind == GeneratorKind.CPlusPlus)
GenerateAcessorMethods(field, prop); GenerateAcessorMethods(field, prop);
// do not rename value-class fields because they would be // do not rename value-class fields because they would be

12
src/Generator/Passes/RenamePass.cs

@ -163,7 +163,7 @@ namespace CppSharp.Passes
string newName; string newName;
if (!Rename(decl, out newName) || AreThereConflicts(decl, newName)) if (!Rename(decl, out newName) || AreThereConflicts(decl, newName))
return false; return false;
decl.Name = newName; decl.Name = newName;
return true; return true;
} }
@ -266,6 +266,16 @@ namespace CppSharp.Passes
return true; return true;
} }
public override bool VisitEnumDecl(Enumeration @enum)
{
VisitDeclaration(@enum);
foreach (var item in @enum.Items)
VisitEnumItemDecl(item);
return true;
}
public override bool VisitFieldDecl(Field field) public override bool VisitFieldDecl(Field field)
{ {
return VisitDeclaration(field); return VisitDeclaration(field);

52
src/Generator/Types/DeclMap.cs

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

85
src/Generator/Types/DeclMapDatabase.cs

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

64
src/Generator/Types/TypeMap.cs

@ -2,6 +2,7 @@
using CppSharp.AST; using CppSharp.AST;
using CppSharp.Generators; using CppSharp.Generators;
using CppSharp.Generators.AST; using CppSharp.Generators.AST;
using CppSharp.Generators.C;
using CppSharp.Generators.CLI; using CppSharp.Generators.CLI;
using CppSharp.Generators.Cpp; using CppSharp.Generators.Cpp;
using CppSharp.Generators.CSharp; using CppSharp.Generators.CSharp;
@ -54,14 +55,15 @@ namespace CppSharp.Types
{ {
switch (kind) switch (kind)
{ {
case GeneratorKind.CPlusPlus: case GeneratorKind.C:
return CppSignatureType(ctx); case GeneratorKind.CPlusPlus:
case GeneratorKind.CLI: return CppSignatureType(ctx);
return CLISignatureType(ctx); case GeneratorKind.CLI:
case GeneratorKind.CSharp: return CLISignatureType(ctx);
return CSharpSignatureType(ctx); case GeneratorKind.CSharp:
default: return CSharpSignatureType(ctx);
throw new System.NotImplementedException(); default:
throw new System.NotImplementedException();
} }
} }
@ -69,17 +71,18 @@ namespace CppSharp.Types
{ {
switch (kind) switch (kind)
{ {
case GeneratorKind.CPlusPlus: case GeneratorKind.C:
CppMarshalToNative(ctx); case GeneratorKind.CPlusPlus:
return; CppMarshalToNative(ctx);
case GeneratorKind.CLI: return;
CLIMarshalToNative(ctx); case GeneratorKind.CLI:
return; CLIMarshalToNative(ctx);
case GeneratorKind.CSharp: return;
CSharpMarshalToNative(ctx as CSharpMarshalContext); case GeneratorKind.CSharp:
return; CSharpMarshalToNative(ctx as CSharpMarshalContext);
default: return;
throw new System.NotImplementedException(); default:
throw new System.NotImplementedException();
} }
} }
@ -87,17 +90,18 @@ namespace CppSharp.Types
{ {
switch (kind) switch (kind)
{ {
case GeneratorKind.CPlusPlus: case GeneratorKind.C:
CppMarshalToManaged(ctx); case GeneratorKind.CPlusPlus:
return; CppMarshalToManaged(ctx);
case GeneratorKind.CLI: return;
CLIMarshalToManaged(ctx); case GeneratorKind.CLI:
return; CLIMarshalToManaged(ctx);
case GeneratorKind.CSharp: return;
CSharpMarshalToManaged(ctx as CSharpMarshalContext); case GeneratorKind.CSharp:
return; CSharpMarshalToManaged(ctx as CSharpMarshalContext);
default: return;
throw new System.NotImplementedException(); default:
throw new System.NotImplementedException();
} }
} }

7
tests/Native/AST.h

@ -253,3 +253,10 @@ int non_deprecated_func(int num);
TestTemplateClass<double> returnIncompleteTemplateSpecialization(); TestTemplateClass<double> returnIncompleteTemplateSpecialization();
#define MACRO(x, y, z) x##y##z #define MACRO(x, y, z) x##y##z
typedef char MyChar;
class TestTypePrinting
{
void ConstPointerTypedef(const MyChar*);
};
Loading…
Cancel
Save