Browse Source

WIP changes 2.

wip
João Matos 5 years ago
parent
commit
48f67256e8
  1. 1
      .gitignore
  2. 2
      build/LLVM-commit
  3. 9
      build/premake5.lua
  4. 977
      include/FastDelegates.h
  5. 5
      src/AST/ASTVisitor.cs
  6. 14
      src/AST/ClassExtensions.cs
  7. 4
      src/AST/Declaration.cs
  8. 1
      src/AST/FunctionExtensions.cs
  9. 2
      src/AST/Method.cs
  10. 1
      src/AST/TranslationUnit.cs
  11. 16
      src/AST/Type.cs
  12. 42
      src/CLI/CLI.cs
  13. 115
      src/CLI/Generator.cs
  14. 2
      src/CLI/Options.cs
  15. 14
      src/CppParser/Bootstrap/Bootstrap.cs
  16. 26
      src/Generator/Driver.cs
  17. 49
      src/Generator/Generator.cs
  18. 16
      src/Generator/Generators/C/CCodeGenerator.cs
  19. 2
      src/Generator/Generators/C/CGenerator.cs
  20. 26
      src/Generator/Generators/C/CppGenerator.cs
  21. 107
      src/Generator/Generators/C/CppHeaders.cs
  22. 181
      src/Generator/Generators/C/CppSources.cs
  23. 15
      src/Generator/Generators/C/CppTypePrinter.cs
  24. 41
      src/Generator/Generators/C/NAPI/NAPIGenerator.cs
  25. 12
      src/Generator/Generators/C/NAPI/NAPIModule.cs
  26. 23
      src/Generator/Generators/C/NAPI/NAPISources.cs
  27. 6
      src/Generator/Generators/CLI/CLITypeReferences.cs
  28. 23
      src/Generator/Generators/CSharp/CSharpGenerator.cs
  29. 5
      src/Generator/Generators/CodeGenerator.cs
  30. 5
      src/Generator/Generators/TypePrinter.cs
  31. 6
      src/Generator/Library.cs
  32. 6
      src/Generator/Options.cs
  33. 1
      src/Generator/Passes/CheckDuplicatedNamesPass.cs
  34. 36
      src/Generator/Passes/CheckIgnoredDecls.cs
  35. 71
      src/Generator/Passes/Pass.cs
  36. 10
      src/Generator/Passes/RenamePass.cs
  37. 6
      src/Generator/Types/DeclMapDatabase.cs
  38. 14
      src/Generator/Utils/BlockGenerator.cs
  39. 1
      src/Generator/Utils/TextGenerator.cs
  40. 20
      tests/CSharp/CSharp.cs

1
.gitignore vendored

@ -46,6 +46,7 @@ src/generator/generator @@ -46,6 +46,7 @@ src/generator/generator
/build/headers
/build/netcore
/deps/llvm
/deps/llvm-download
/deps/NUnit*
/extra
/include/include

2
build/LLVM-commit

@ -1 +1 @@ @@ -1 +1 @@
80c3ea4e633b440cb4bc2c36856d811353e474bb
462b960de8c48a933543736908ca8cbda21900a4

9
build/premake5.lua

@ -46,11 +46,10 @@ if not _OPTIONS["disable-tests"] then @@ -46,11 +46,10 @@ if not _OPTIONS["disable-tests"] then
IncludeTests()
end
if not _OPTIONS["disable-tests"] then
if string.starts(action, "vs") then
--if not _OPTIONS["disable-tests"] then
--if string.starts(action, "vs") then
group "Examples"
IncludeExamples()
end
end
--end
--end

977
include/FastDelegates.h

@ -0,0 +1,977 @@ @@ -0,0 +1,977 @@
// FastDelegate.hpp
// Efficient delegates in C++ that generate only two lines of asm code!
// Documentation is found at http://www.codeproject.com/cpp/FastDelegate.asp
//
// - Don Clugston, Mar 2004.
// Major contributions were made by Jody Hagins.
// Version 2.0 by Pa<EFBFBD>l Jim<EFBFBD>nez.
// Version 2.0.1 by Benjamin YanXiang Huang
//
// History:
// 24-Apr-04 1.0 * Submitted to CodeProject.
// 28-Apr-04 1.1 * Prevent most unsafe uses of evil static function hack.
// * Improved syntax for horrible_cast (thanks Paul Bludov).
// * Tested on Metrowerks MWCC and Intel ICL (IA32)
// * Compiled, but not run, on Comeau C++ and Intel Itanium ICL.
// 27-Jun-04 1.2 * Now works on Borland C++ Builder 5.5
// * Now works on /clr "managed C++" code on VC7, VC7.1
// * Comeau C++ now compiles without warnings.
// * Prevent the virtual inheritance case from being used on
// VC6 and earlier, which generate incorrect code.
// * Improved warning and error messages. Non-standard hacks
// now have compile-time checks to make them safer.
// * implicit_cast used instead of static_cast in many cases.
// * If calling a const member function, a const class pointer can be used.
// * MakeDelegate() global helper function added to simplify pass-by-value.
// * Added fastdelegate.clear()
// 16-Jul-04 1.2.1* Workaround for gcc bug (const member function pointers in templates)
// 30-Oct-04 1.3 * Support for (non-void) return values.
// * No more workarounds in client code!
// MSVC and Intel now use a clever hack invented by John Dlugosz:
// - The FASTDELEGATEDECLARE workaround is no longer necessary.
// - No more warning messages for VC6
// * Less use of macros. Error messages should be more comprehensible.
// * Added include guards
// * Added FastDelegate::empty() to test if invocation is safe (Thanks Neville Franks).
// * Now tested on VS 2005 Express Beta, PGI C++
// 24-Dec-04 1.4 * Added DelegateMemento, to allow collections of disparate delegates.
// * <,>,<=,>= comparison operators to allow storage in ordered containers.
// * Substantial reduction of code size, especially the 'Closure' class.
// * Standardised all the compiler-specific workarounds.
// * MFP conversion now works for CodePlay (but not yet supported in the full code).
// * Now compiles without warnings on _any_ supported compiler, including BCC 5.5.1
// * New syntax: FastDelegate< int (char *, double) >.
// 14-Feb-05 1.4.1* Now treats =0 as equivalent to .clear(), ==0 as equivalent to .empty(). (Thanks elfric).
// * Now tested on Intel ICL for AMD64, VS2005 Beta for AMD64 and Itanium.
// 30-Mar-05 1.5 * Safebool idiom: "if (dg)" is now equivalent to "if (!dg.empty())"
// * Fully supported by CodePlay VectorC
// * Bugfix for Metrowerks: empty() was buggy because a valid MFP can be 0 on MWCC!
// * More optimal assignment,== and != operators for static function pointers.
// 06-Feb-13 2.0 * GetMemento is now const
// * Added hash method that makes use of new unchecked function unsafe_horrible_cast
// * Removed VC6 code
// * Use variadic templates (C++11)
// * Added MakeDelegate for plain function pointers
// * Use static_assert for compile-time checks (C++11)
// 21-Jan-14 2.0.1* Fixed 2 typos (line 393 & 429) where a static_cast should have been a static_assert.
// 21-Jun-14 2.0.2* Fixed incorrect union member name in the SimplifyMemFunc struct.
#ifndef FASTDELEGATE_HPP
#define FASTDELEGATE_HPP
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include <cstring> // to allow <,> comparisons
////////////////////////////////////////////////////////////////////////////////
// Configuration options
//
////////////////////////////////////////////////////////////////////////////////
// Uncomment the following #define for optimally-sized delegates.
// In this case, the generated asm code is almost identical to the code you'd get
// if the compiler had native support for delegates.
// It will not work on systems where sizeof(dataptr) < sizeof(codeptr).
// Thus, it will not work for DOS compilers using the medium model.
// It will also probably fail on some DSP systems.
#define FASTDELEGATE_USESTATICFUNCTIONHACK
// Uncomment the next line to allow function declarator syntax.
// It is automatically enabled for those compilers where it is known to work.
//#define FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX
////////////////////////////////////////////////////////////////////////////////
// Compiler identification for workarounds
//
////////////////////////////////////////////////////////////////////////////////
// Compiler identification. It's not easy to identify Visual C++ because
// many vendors fraudulently define Microsoft's identifiers.
#if defined(_MSC_VER) && !defined(__MWERKS__) && !defined(__VECTOR_C) && !defined(__ICL) && !defined(__BORLANDC__)
#define FASTDLGT_ISMSVC
#endif
// Does the compiler uses Microsoft's member function pointer structure?
// If so, it needs special treatment.
// Metrowerks CodeWarrior, Intel, and CodePlay fraudulently define Microsoft's
// identifier, _MSC_VER. We need to filter Metrowerks out.
#if defined(_MSC_VER) && !defined(__MWERKS__)
#define FASTDLGT_MICROSOFT_MFP
#if !defined(__VECTOR_C)
// CodePlay doesn't have the __single/multi/virtual_inheritance keywords
#define FASTDLGT_HASINHERITANCE_KEYWORDS
#endif
#endif
// Does it allow function declarator syntax? The following compilers are known to work:
#if defined(FASTDLGT_ISMSVC) && (_MSC_VER >=1310) // VC 7.1
#define FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX
#endif
// Gcc(2.95+), and versions of Digital Mars, Intel and Comeau in common use.
#if defined (__DMC__) || defined(__GNUC__) || defined(__ICL) || defined(__COMO__)
#define FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX
#endif
// It works on Metrowerks MWCC 3.2.2. From boost.Config it should work on earlier ones too.
#if defined (__MWERKS__)
#define FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX
#endif
#ifdef __GNUC__ // Workaround GCC bug #8271
// At present, GCC doesn't recognize constness of MFPs in templates
#define FASTDELEGATE_GCC_BUG_8271
#endif
////////////////////////////////////////////////////////////////////////////////
// General tricks used in this code
//
// (a) Error messages are generated by typdefing an array of negative size to
// generate compile-time errors.
// (b) Warning messages on MSVC are generated by declaring unused variables, and
// enabling the "variable XXX is never used" warning.
// (c) Unions are used in a few compiler-specific cases to perform illegal casts.
// (d) For Microsoft and Intel, when adjusting the 'this' pointer, it's cast to
// (char *) first to ensure that the correct number of *bytes* are added.
//
////////////////////////////////////////////////////////////////////////////////
// Helper templates
//
////////////////////////////////////////////////////////////////////////////////
namespace fastdelegate {
namespace detail { // we'll hide the implementation details in a nested namespace.
// implicit_cast< >
// I believe this was originally going to be in the C++ standard but
// was left out by accident. It's even milder than static_cast.
// I use it instead of static_cast<> to emphasize that I'm not doing
// anything nasty.
// Usage is identical to static_cast<>
template <class OutputClass, class InputClass>
inline OutputClass implicit_cast(InputClass input){
return input;
}
// horrible_cast< >
// This is truly evil. It completely subverts C++'s type system, allowing you
// to cast from any class to any other class. Technically, using a union
// to perform the cast is undefined behaviour (even in C). But we can see if
// it is OK by checking that the union is the same size as each of its members.
// horrible_cast<> should only be used for compiler-specific workarounds.
// Usage is identical to reinterpret_cast<>.
// This union is declared outside the horrible_cast because BCC 5.5.1
// can't inline a function with a nested class, and gives a warning.
template <class OutputClass, class InputClass>
union horrible_union{
OutputClass out;
InputClass in;
};
template <class OutputClass, class InputClass>
inline OutputClass horrible_cast(const InputClass input){
horrible_union<OutputClass, InputClass> u;
// Cause a compile-time error if in, out and u are not the same size.
// If the compile fails here, it means the compiler has peculiar
// unions which would prevent the cast from working.
static_assert(sizeof(InputClass)==sizeof(u) && sizeof(InputClass)==sizeof(OutputClass), "Cannot use horrible_cast<>");
u.in = input;
return u.out;
}
template <class OutputClass, class InputClass>
inline OutputClass unsafe_horrible_cast(const InputClass input){
horrible_union<OutputClass, InputClass> u;
u.in = input;
return u.out;
}
////////////////////////////////////////////////////////////////////////////////
// Workarounds
//
////////////////////////////////////////////////////////////////////////////////
// Backwards compatibility: This macro used to be necessary in the virtual inheritance
// case for Intel and Microsoft. Now it just forward-declares the class.
#define FASTDELEGATEDECLARE(CLASSNAME) class CLASSNAME;
// Prevent use of the static function hack with the DOS medium model.
#ifdef __MEDIUM__
#undef FASTDELEGATE_USESTATICFUNCTIONHACK
#endif
typedef void DefaultVoid;
// Translate from 'DefaultVoid' to 'void'.
// Everything else is unchanged
template <class T>
struct DefaultVoidToVoid { typedef T type; };
template <>
struct DefaultVoidToVoid<DefaultVoid> { typedef void type; };
// Translate from 'void' into 'DefaultVoid'
// Everything else is unchanged
template <class T>
struct VoidToDefaultVoid { typedef T type; };
template <>
struct VoidToDefaultVoid<void> { typedef DefaultVoid type; };
////////////////////////////////////////////////////////////////////////////////
// Fast Delegates, part 1:
//
// Conversion of member function pointer to a standard form
//
////////////////////////////////////////////////////////////////////////////////
// GenericClass is a fake class, ONLY used to provide a type.
// It is vitally important that it is never defined, so that the compiler doesn't
// think it can optimize the invocation. For example, Borland generates simpler
// code if it knows the class only uses single inheritance.
// Compilers using Microsoft's structure need to be treated as a special case.
#ifdef FASTDLGT_MICROSOFT_MFP
#ifdef FASTDLGT_HASINHERITANCE_KEYWORDS
// For Microsoft and Intel, we want to ensure that it's the most efficient type of MFP
// (4 bytes), even when the /vmg option is used. Declaring an empty class
// would give 16 byte pointers in this case....
class __single_inheritance GenericClass;
#endif
// ...but for Codeplay, an empty class *always* gives 4 byte pointers.
// If compiled with the /clr option ("managed C++"), the JIT compiler thinks
// it needs to load GenericClass before it can call any of its functions,
// (compiles OK but crashes at runtime!), so we need to declare an
// empty class to make it happy.
// Codeplay and VC4 can't cope with the unknown_inheritance case either.
class GenericClass {};
#else
class GenericClass;
#endif
// The size of a single inheritance member function pointer.
const int SINGLE_MEMFUNCPTR_SIZE = sizeof(void (GenericClass::*)());
// SimplifyMemFunc< >::Convert()
//
// A template function that converts an arbitrary member function pointer into the
// simplest possible form of member function pointer, using a supplied 'this' pointer.
// According to the standard, this can be done legally with reinterpret_cast<>.
// For (non-standard) compilers which use member function pointers which vary in size
// depending on the class, we need to use knowledge of the internal structure of a
// member function pointer, as used by the compiler. Template specialization is used
// to distinguish between the sizes. Because some compilers don't support partial
// template specialisation, I use full specialisation of a wrapper struct.
// general case -- don't know how to convert it. Force a compile failure
template <int N>
struct SimplifyMemFunc {
template <class X, class XFuncType, class GenericMemFuncType>
inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind,
GenericMemFuncType &bound_func) {
// Unsupported member function type -- force a compile failure.
// (it's illegal to have a array with negative size).
static_assert(N - 100, "Unsupported member function pointer on this compiler");
return 0;
}
};
// For compilers where all member func ptrs are the same size, everything goes here.
// For non-standard compilers, only single_inheritance classes go here.
template <>
struct SimplifyMemFunc<SINGLE_MEMFUNCPTR_SIZE> {
template <class X, class XFuncType, class GenericMemFuncType>
inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind,
GenericMemFuncType &bound_func) {
#if defined __DMC__
// Digital Mars doesn't allow you to cast between abitrary PMF's,
// even though the standard says you can. The 32-bit compiler lets you
// static_cast through an int, but the DOS compiler doesn't.
bound_func = horrible_cast<GenericMemFuncType>(function_to_bind);
#else
bound_func = reinterpret_cast<GenericMemFuncType>(function_to_bind);
#endif
return reinterpret_cast<GenericClass *>(pthis);
}
};
////////////////////////////////////////////////////////////////////////////////
// Fast Delegates, part 1b:
//
// Workarounds for Microsoft and Intel
//
////////////////////////////////////////////////////////////////////////////////
// Compilers with member function pointers which violate the standard (MSVC, Intel, Codeplay),
// need to be treated as a special case.
#ifdef FASTDLGT_MICROSOFT_MFP
// We use unions to perform horrible_casts. I would like to use #pragma pack(push, 1)
// at the start of each function for extra safety, but VC6 seems to ICE
// intermittently if you do this inside a template.
// __multiple_inheritance classes go here
// Nasty hack for Microsoft and Intel (IA32 and Itanium)
template<>
struct SimplifyMemFunc< SINGLE_MEMFUNCPTR_SIZE + sizeof(int) > {
template <class X, class XFuncType, class GenericMemFuncType>
inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind,
GenericMemFuncType &bound_func) {
// We need to use a horrible_cast to do this conversion.
// In MSVC, a multiple inheritance member pointer is internally defined as:
union {
XFuncType func;
struct {
GenericMemFuncType funcaddress; // points to the actual member function
int delta; // #BYTES to be added to the 'this' pointer
}s;
} u;
// Check that the horrible_cast will work
static_assert(sizeof(function_to_bind)==sizeof(u.s), "Cannot use horrible_cast<>");
u.func = function_to_bind;
bound_func = u.s.funcaddress;
return reinterpret_cast<GenericClass *>(reinterpret_cast<char *>(pthis) + u.s.delta);
}
};
// virtual inheritance is a real nuisance. It's inefficient and complicated.
// On MSVC and Intel, there isn't enough information in the pointer itself to
// enable conversion to a closure pointer. Earlier versions of this code didn't
// work for all cases, and generated a compile-time error instead.
// But a very clever hack invented by John M. Dlugosz solves this problem.
// My code is somewhat different to his: I have no asm code, and I make no
// assumptions about the calling convention that is used.
// In VC++ and ICL, a virtual_inheritance member pointer
// is internally defined as:
struct MicrosoftVirtualMFP {
void (GenericClass::*codeptr)(); // points to the actual member function
int delta; // #bytes to be added to the 'this' pointer
int vtable_index; // or 0 if no virtual inheritance
};
// The CRUCIAL feature of Microsoft/Intel MFPs which we exploit is that the
// m_codeptr member is *always* called, regardless of the values of the other
// members. (This is *not* true for other compilers, eg GCC, which obtain the
// function address from the vtable if a virtual function is being called).
// Dlugosz's trick is to make the codeptr point to a probe function which
// returns the 'this' pointer that was used.
// Define a generic class that uses virtual inheritance.
// It has a trival member function that returns the value of the 'this' pointer.
struct GenericVirtualClass : virtual public GenericClass
{
typedef GenericVirtualClass * (GenericVirtualClass::*ProbePtrType)();
GenericVirtualClass * GetThis() { return this; }
};
// __virtual_inheritance classes go here
template <>
struct SimplifyMemFunc<SINGLE_MEMFUNCPTR_SIZE + 2*sizeof(int) >
{
template <class X, class XFuncType, class GenericMemFuncType>
inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind,
GenericMemFuncType &bound_func) {
union {
XFuncType func;
GenericClass* (X::*ProbeFunc)();
MicrosoftVirtualMFP s;
} u;
u.func = function_to_bind;
bound_func = reinterpret_cast<GenericMemFuncType>(u.s.codeptr);
union {
GenericVirtualClass::ProbePtrType virtfunc;
MicrosoftVirtualMFP s;
} u2;
// Check that the horrible_cast<>s will work
static_assert(sizeof(function_to_bind)==sizeof(u.s) && sizeof(function_to_bind)==sizeof(u.ProbeFunc) && sizeof(u2.virtfunc)==sizeof(u2.s), "Cannot use horrible_cast<>");
/*typedef int ERROR_CantUsehorrible_cast[sizeof(function_to_bind)==sizeof(u.s)
&& sizeof(function_to_bind)==sizeof(u.ProbeFunc)
&& sizeof(u2.virtfunc)==sizeof(u2.s) ? 1 : -1];*/
// Unfortunately, taking the address of a MF prevents it from being inlined, so
// this next line can't be completely optimised away by the compiler.
u2.virtfunc = &GenericVirtualClass::GetThis;
u.s.codeptr = u2.s.codeptr;
return (pthis->*u.ProbeFunc)();
}
};
// Nasty hack for Microsoft and Intel (IA32 and Itanium)
// unknown_inheritance classes go here
// This is probably the ugliest bit of code I've ever written. Look at the casts!
// There is a compiler bug in MSVC6 which prevents it from using this code.
template <>
struct SimplifyMemFunc<SINGLE_MEMFUNCPTR_SIZE + 3*sizeof(int) >
{
template <class X, class XFuncType, class GenericMemFuncType>
inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind,
GenericMemFuncType &bound_func) {
// The member function pointer is 16 bytes long. We can't use a normal cast, but
// we can use a union to do the conversion.
union {
XFuncType func;
// In VC++ and ICL, an unknown_inheritance member pointer
// is internally defined as:
struct {
GenericMemFuncType funcaddress; // points to the actual member function
int delta; // #bytes to be added to the 'this' pointer
int vtordisp; // #bytes to add to 'this' to find the vtable
int vtable_index; // or 0 if no virtual inheritance
} s;
} u;
// Check that the horrible_cast will work
static_assert(sizeof(XFuncType)==sizeof(u.s), "Cannot use horrible_cast<>");
//typedef int ERROR_CantUsehorrible_cast[sizeof(XFuncType)==sizeof(u.s)? 1 : -1];
u.func = function_to_bind;
bound_func = u.s.funcaddress;
int virtual_delta = 0;
if (u.s.vtable_index) { // Virtual inheritance is used
// First, get to the vtable.
// It is 'vtordisp' bytes from the start of the class.
const int * vtable = *reinterpret_cast<const int *const*>(
reinterpret_cast<const char *>(pthis) + u.s.vtordisp );
// 'vtable_index' tells us where in the table we should be looking.
virtual_delta = u.s.vtordisp + *reinterpret_cast<const int *>(
reinterpret_cast<const char *>(vtable) + u.s.vtable_index);
}
// The int at 'virtual_delta' gives us the amount to add to 'this'.
// Finally we can add the three components together. Phew!
return reinterpret_cast<GenericClass *>(
reinterpret_cast<char *>(pthis) + u.s.delta + virtual_delta);
};
};
#endif // MS/Intel hacks
} // namespace detail
////////////////////////////////////////////////////////////////////////////////
// Fast Delegates, part 2:
//
// Define the delegate storage, and cope with static functions
//
////////////////////////////////////////////////////////////////////////////////
// DelegateMemento -- an opaque structure which can hold an arbitary delegate.
// It knows nothing about the calling convention or number of arguments used by
// the function pointed to.
// It supplies comparison operators so that it can be stored in STL collections.
// It cannot be set to anything other than null, nor invoked directly:
// it must be converted to a specific delegate.
// Implementation:
// There are two possible implementations: the Safe method and the Evil method.
// DelegateMemento - Safe version
//
// This implementation is standard-compliant, but a bit tricky.
// A static function pointer is stored inside the class.
// Here are the valid values:
// +-- Static pointer --+--pThis --+-- pMemFunc-+-- Meaning------+
// | 0 | 0 | 0 | Empty |
// | !=0 |(dontcare)| Invoker | Static function|
// | 0 | !=0 | !=0* | Method call |
// +--------------------+----------+------------+----------------+
// * For Metrowerks, this can be 0. (first virtual function in a
// single_inheritance class).
// When stored stored inside a specific delegate, the 'dontcare' entries are replaced
// with a reference to the delegate itself. This complicates the = and == operators
// for the delegate class.
// DelegateMemento - Evil version
//
// For compilers where data pointers are at least as big as code pointers, it is
// possible to store the function pointer in the this pointer, using another
// horrible_cast. In this case the DelegateMemento implementation is simple:
// +--pThis --+-- pMemFunc-+-- Meaning---------------------+
// | 0 | 0 | Empty |
// | !=0 | !=0* | Static function or method call|
// +----------+------------+-------------------------------+
// * For Metrowerks, this can be 0. (first virtual function in a
// single_inheritance class).
// Note that the Sun C++ and MSVC documentation explicitly state that they
// support static_cast between void * and function pointers.
class DelegateMemento {
protected:
// the data is protected, not private, because many
// compilers have problems with template friends.
typedef void (detail::GenericClass::*GenericMemFuncType)(); // arbitrary MFP.
detail::GenericClass *m_pthis;
GenericMemFuncType m_pFunction;
#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)
typedef void (*GenericFuncPtr)(); // arbitrary code pointer
GenericFuncPtr m_pStaticFunction;
#endif
public:
#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)
DelegateMemento() : m_pthis(0), m_pFunction(0), m_pStaticFunction(0) {};
void clear() {
m_pthis=0; m_pFunction=0; m_pStaticFunction=0;
}
#else
DelegateMemento() : m_pthis(0), m_pFunction(0) {};
void clear() { m_pthis=0; m_pFunction=0; }
#endif
public:
#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)
inline bool IsEqual (const DelegateMemento &x) const{
// We have to cope with the static function pointers as a special case
if (m_pFunction!=x.m_pFunction) return false;
// the static function ptrs must either both be equal, or both be 0.
if (m_pStaticFunction!=x.m_pStaticFunction) return false;
if (m_pStaticFunction!=0) return m_pthis==x.m_pthis;
else return true;
}
#else // Evil Method
inline bool IsEqual (const DelegateMemento &x) const{
return m_pthis==x.m_pthis && m_pFunction==x.m_pFunction;
}
#endif
// Provide a strict weak ordering for DelegateMementos.
inline bool IsLess(const DelegateMemento &right) const {
// deal with static function pointers first
#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)
if (m_pStaticFunction !=0 || right.m_pStaticFunction!=0)
return m_pStaticFunction < right.m_pStaticFunction;
#endif
if (m_pthis !=right.m_pthis) return m_pthis < right.m_pthis;
// There are no ordering operators for member function pointers,
// but we can fake one by comparing each byte. The resulting ordering is
// arbitrary (and compiler-dependent), but it permits storage in ordered STL containers.
return std::memcmp(&m_pFunction, &right.m_pFunction, sizeof(m_pFunction)) < 0;
}
// Provide a simple hashing method.
inline size_t Hash() const {
return reinterpret_cast<size_t>(m_pthis) ^ detail::unsafe_horrible_cast<size_t>(m_pFunction);
}
// BUGFIX (Mar 2005):
// We can't just compare m_pFunction because on Metrowerks,
// m_pFunction can be zero even if the delegate is not empty!
inline bool operator ! () const // Is it bound to anything?
{ return m_pthis==0 && m_pFunction==0; }
inline bool empty() const // Is it bound to anything?
{ return m_pthis==0 && m_pFunction==0; }
public:
DelegateMemento & operator = (const DelegateMemento &right) {
SetMementoFrom(right);
return *this;
}
inline bool operator <(const DelegateMemento &right) {
return IsLess(right);
}
inline bool operator >(const DelegateMemento &right) {
return right.IsLess(*this);
}
DelegateMemento (const DelegateMemento &right) :
m_pthis(right.m_pthis), m_pFunction(right.m_pFunction)
#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)
, m_pStaticFunction (right.m_pStaticFunction)
#endif
{}
protected:
void SetMementoFrom(const DelegateMemento &right) {
m_pFunction = right.m_pFunction;
m_pthis = right.m_pthis;
#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)
m_pStaticFunction = right.m_pStaticFunction;
#endif
}
};
// ClosurePtr<>
//
// A private wrapper class that adds function signatures to DelegateMemento.
// It's the class that does most of the actual work.
// The signatures are specified by:
// GenericMemFunc: must be a type of GenericClass member function pointer.
// StaticFuncPtr: must be a type of function pointer with the same signature
// as GenericMemFunc.
// UnvoidStaticFuncPtr: is the same as StaticFuncPtr, except on VC6
// where it never returns void (returns DefaultVoid instead).
// An outer class, FastDelegateN<>, handles the invoking and creates the
// necessary typedefs.
// This class does everything else.
namespace detail {
template < class GenericMemFunc, class StaticFuncPtr, class UnvoidStaticFuncPtr>
class ClosurePtr : public DelegateMemento {
public:
// These functions are for setting the delegate to a member function.
// Here's the clever bit: we convert an arbitrary member function into a
// standard form. XMemFunc should be a member function of class X, but I can't
// enforce that here. It needs to be enforced by the wrapper class.
template < class X, class XMemFunc >
inline void bindmemfunc(X *pthis, XMemFunc function_to_bind ) {
m_pthis = SimplifyMemFunc< sizeof(function_to_bind) >
::Convert(pthis, function_to_bind, m_pFunction);
#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)
m_pStaticFunction = 0;
#endif
}
// For const member functions, we only need a const class pointer.
// Since we know that the member function is const, it's safe to
// remove the const qualifier from the 'this' pointer with a const_cast.
// VC6 has problems if we just overload 'bindmemfunc', so we give it a different name.
template < class X, class XMemFunc>
inline void bindconstmemfunc(const X *pthis, XMemFunc function_to_bind) {
m_pthis= SimplifyMemFunc< sizeof(function_to_bind) >
::Convert(const_cast<X*>(pthis), function_to_bind, m_pFunction);
#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)
m_pStaticFunction = 0;
#endif
}
#ifdef FASTDELEGATE_GCC_BUG_8271 // At present, GCC doesn't recognize constness of MFPs in templates
template < class X, class XMemFunc>
inline void bindmemfunc(const X *pthis, XMemFunc function_to_bind) {
bindconstmemfunc(pthis, function_to_bind);
#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)
m_pStaticFunction = 0;
#endif
}
#endif
// These functions are required for invoking the stored function
inline GenericClass *GetClosureThis() const { return m_pthis; }
inline GenericMemFunc GetClosureMemPtr() const { return reinterpret_cast<GenericMemFunc>(m_pFunction); }
// There are a few ways of dealing with static function pointers.
// There's a standard-compliant, but tricky method.
// There's also a straightforward hack, that won't work on DOS compilers using the
// medium memory model. It's so evil that I can't recommend it, but I've
// implemented it anyway because it produces very nice asm code.
#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)
// ClosurePtr<> - Safe version
//
// This implementation is standard-compliant, but a bit tricky.
// I store the function pointer inside the class, and the delegate then
// points to itself. Whenever the delegate is copied, these self-references
// must be transformed, and this complicates the = and == operators.
public:
// The next two functions are for operator ==, =, and the copy constructor.
// We may need to convert the m_pthis pointers, so that
// they remain as self-references.
template< class DerivedClass >
inline void CopyFrom (DerivedClass *pParent, const DelegateMemento &x) {
SetMementoFrom(x);
if (m_pStaticFunction!=0) {
// transform self references...
m_pthis=reinterpret_cast<GenericClass *>(pParent);
}
}
// For static functions, the 'static_function_invoker' class in the parent
// will be called. The parent then needs to call GetStaticFunction() to find out
// the actual function to invoke.
template < class DerivedClass, class ParentInvokerSig >
inline void bindstaticfunc(DerivedClass *pParent, ParentInvokerSig static_function_invoker,
StaticFuncPtr function_to_bind ) {
if (function_to_bind==0) { // cope with assignment to 0
m_pFunction=0;
} else {
bindmemfunc(pParent, static_function_invoker);
}
m_pStaticFunction=reinterpret_cast<GenericFuncPtr>(function_to_bind);
}
inline UnvoidStaticFuncPtr GetStaticFunction() const {
return reinterpret_cast<UnvoidStaticFuncPtr>(m_pStaticFunction);
}
#else
// ClosurePtr<> - Evil version
//
// For compilers where data pointers are at least as big as code pointers, it is
// possible to store the function pointer in the this pointer, using another
// horrible_cast. Invocation isn't any faster, but it saves 4 bytes, and
// speeds up comparison and assignment. If C++ provided direct language support
// for delegates, they would produce asm code that was almost identical to this.
// Note that the Sun C++ and MSVC documentation explicitly state that they
// support static_cast between void * and function pointers.
template< class DerivedClass >
inline void CopyFrom (DerivedClass * /*pParent*/, const DelegateMemento &right) {
SetMementoFrom(right);
}
// For static functions, the 'static_function_invoker' class in the parent
// will be called. The parent then needs to call GetStaticFunction() to find out
// the actual function to invoke.
// ******** EVIL, EVIL CODE! *******
template < class DerivedClass, class ParentInvokerSig>
inline void bindstaticfunc(DerivedClass *pParent, ParentInvokerSig static_function_invoker,
StaticFuncPtr function_to_bind) {
if (function_to_bind==0) { // cope with assignment to 0
m_pFunction=0;
} else {
// We'll be ignoring the 'this' pointer, but we need to make sure we pass
// a valid value to bindmemfunc().
bindmemfunc(pParent, static_function_invoker);
}
// WARNING! Evil hack. We store the function in the 'this' pointer!
// Ensure that there's a compilation failure if function pointers
// and data pointers have different sizes.
// If you get this error, you need to #undef FASTDELEGATE_USESTATICFUNCTIONHACK.
static_assert(sizeof(GenericClass *)==sizeof(function_to_bind), "Cannot use evil method");
m_pthis = horrible_cast<GenericClass *>(function_to_bind);
// MSVC, SunC++ and DMC accept the following (non-standard) code:
// m_pthis = static_cast<GenericClass *>(static_cast<void *>(function_to_bind));
// BCC32, Comeau and DMC accept this method. MSVC7.1 needs __int64 instead of long
// m_pthis = reinterpret_cast<GenericClass *>(reinterpret_cast<long>(function_to_bind));
}
// ******** EVIL, EVIL CODE! *******
// This function will be called with an invalid 'this' pointer!!
// We're just returning the 'this' pointer, converted into
// a function pointer!
inline UnvoidStaticFuncPtr GetStaticFunction() const {
// Ensure that there's a compilation failure if function pointers
// and data pointers have different sizes.
// If you get this error, you need to #undef FASTDELEGATE_USESTATICFUNCTIONHACK.
static_assert(sizeof(UnvoidStaticFuncPtr)==sizeof(this), "Cannot use evil method");
return horrible_cast<UnvoidStaticFuncPtr>(this);
}
#endif // !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)
// Does the closure contain this static function?
inline bool IsEqualToStaticFuncPtr(StaticFuncPtr funcptr){
if (funcptr==0) return empty();
// For the Evil method, if it doesn't actually contain a static function, this will return an arbitrary
// value that is not equal to any valid function pointer.
else return funcptr==reinterpret_cast<StaticFuncPtr>(GetStaticFunction());
}
};
} // namespace detail
////////////////////////////////////////////////////////////////////////////////
// Fast Delegates, part 3:
//
// Wrapper classes to ensure type safety
//
////////////////////////////////////////////////////////////////////////////////
// Once we have the member function conversion templates, it's easy to make the
// wrapper classes. So that they will work with as many compilers as possible,
// the classes are of the form
// FastDelegate3<int, char *, double>
// They can cope with any combination of parameters. The max number of parameters
// allowed is 8, but it is trivial to increase this limit.
// Note that we need to treat const member functions seperately.
// All this class does is to enforce type safety, and invoke the delegate with
// the correct list of parameters.
// Because of the weird rule about the class of derived member function pointers,
// you sometimes need to apply a downcast to the 'this' pointer.
// This is the reason for the use of "implicit_cast<X*>(pthis)" in the code below.
// If CDerivedClass is derived from CBaseClass, but doesn't override SimpleVirtualFunction,
// without this trick you'd need to write:
// MyDelegate(static_cast<CBaseClass *>(&d), &CDerivedClass::SimpleVirtualFunction);
// but with the trick you can write
// MyDelegate(&d, &CDerivedClass::SimpleVirtualFunction);
// RetType is the type the compiler uses in compiling the template. For VC6,
// it cannot be void. DesiredRetType is the real type which is returned from
// all of the functions. It can be void.
// Implicit conversion to "bool" is achieved using the safe_bool idiom,
// using member data pointers (MDP). This allows "if (dg)..." syntax
// Because some compilers (eg codeplay) don't have a unique value for a zero
// MDP, an extra padding member is added to the SafeBool struct.
// Some compilers (eg VC6) won't implicitly convert from 0 to an MDP, so
// in that case the static function constructor is not made explicit; this
// allows "if (dg==0) ..." to compile.
template <typename RetType, typename... Args>
class FastDelegateImpl {
private:
typedef typename detail::DefaultVoidToVoid<RetType>::type DesiredRetType;
typedef DesiredRetType (*StaticFunctionPtr)(Args...);
typedef RetType (*UnvoidStaticFunctionPtr)(Args...);
typedef RetType (detail::GenericClass::*GenericMemFn)(Args...);
typedef detail::ClosurePtr<GenericMemFn, StaticFunctionPtr, UnvoidStaticFunctionPtr> ClosureType;
ClosureType m_Closure;
public:
// Typedefs to aid generic programming
typedef FastDelegateImpl type;
// Construction and comparison functions
FastDelegateImpl() { clear(); }
FastDelegateImpl(const FastDelegateImpl &x) {
m_Closure.CopyFrom(this, x.m_Closure); }
void operator = (const FastDelegateImpl &x) {
m_Closure.CopyFrom(this, x.m_Closure); }
bool operator ==(const FastDelegateImpl &x) const {
return m_Closure.IsEqual(x.m_Closure); }
bool operator !=(const FastDelegateImpl &x) const {
return !m_Closure.IsEqual(x.m_Closure); }
bool operator <(const FastDelegateImpl &x) const {
return m_Closure.IsLess(x.m_Closure); }
bool operator >(const FastDelegateImpl &x) const {
return x.m_Closure.IsLess(m_Closure); }
// Binding to non-const member functions
template < typename X, typename Y >
FastDelegateImpl(Y *pthis, DesiredRetType (X::* function_to_bind)(Args... args) ) {
m_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind); }
template < typename X, typename Y >
inline void bind(Y *pthis, DesiredRetType (X::* function_to_bind)(Args... args)) {
m_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind); }
// Binding to const member functions.
template < typename X, typename Y >
FastDelegateImpl(const Y *pthis, DesiredRetType (X::* function_to_bind)(Args... args) const) {
m_Closure.bindconstmemfunc(detail::implicit_cast<const X*>(pthis), function_to_bind); }
template < typename X, typename Y >
inline void bind(const Y *pthis, DesiredRetType (X::* function_to_bind)(Args... args) const) {
m_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis), function_to_bind); }
// Static functions. We convert them into a member function call.
// This constructor also provides implicit conversion
FastDelegateImpl(DesiredRetType (*function_to_bind)(Args... args) ) {
bind(function_to_bind); }
// for efficiency, prevent creation of a temporary
void operator = (DesiredRetType (*function_to_bind)(Args... args) ) {
bind(function_to_bind); }
inline void bind(DesiredRetType (*function_to_bind)(Args... args)) {
m_Closure.bindstaticfunc(this, &FastDelegateImpl::InvokeStaticFunction,
function_to_bind); }
// Invoke the delegate
RetType operator() (Args... args) const {
return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(args...); }
// Implicit conversion to "bool" using the safe_bool idiom
private:
typedef struct SafeBoolStruct {
int a_data_pointer_to_this_is_0_on_buggy_compilers;
StaticFunctionPtr m_nonzero;
} UselessTypedef;
typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type;
public:
operator unspecified_bool_type() const {
return empty()? 0: &SafeBoolStruct::m_nonzero;
}
// necessary to allow ==0 to work despite the safe_bool idiom
inline bool operator==(StaticFunctionPtr funcptr) {
return m_Closure.IsEqualToStaticFuncPtr(funcptr); }
inline bool operator!=(StaticFunctionPtr funcptr) {
return !m_Closure.IsEqualToStaticFuncPtr(funcptr); }
inline bool operator ! () const { // Is it bound to anything?
return !m_Closure; }
inline bool empty() const {
return !m_Closure; }
void clear() { m_Closure.clear();}
// Conversion to and from the DelegateMemento storage class
const DelegateMemento & GetMemento() const { return m_Closure; }
void SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); }
private: // Invoker for static functions
RetType InvokeStaticFunction(Args... args) const {
return (*(m_Closure.GetStaticFunction()))(args...); }
};
////////////////////////////////////////////////////////////////////////////////
// Fast Delegates, part 4:
//
// FastDelegate<> class (Original author: Jody Hagins)
// Allows boost::function style syntax like:
// FastDelegate< double (int, long) >
// instead of:
// FastDelegate2< int, long, double >
//
////////////////////////////////////////////////////////////////////////////////
#ifdef FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX
// Declare FastDelegate as a class template. It will be specialized
// later for all number of arguments.
template <typename Signature>
class FastDelegate;
template <typename RetType, typename... Args>
class FastDelegate<RetType (Args...)>
// Inherit from FastDelegate1 so that it can be treated just like a FastDelegate1
: public FastDelegateImpl < RetType, Args... >
{
public:
// Make using the base type a bit easier via typedef.
typedef FastDelegateImpl < RetType, Args... > BaseType;
// Allow users access to the specific type of this delegate.
typedef FastDelegate SelfType;
// Mimic the base class constructors.
FastDelegate() : BaseType() { }
template < typename X, typename Y >
FastDelegate(Y * pthis,
RetType (X::* function_to_bind)( Args... args ))
: BaseType(pthis, function_to_bind) { }
template < typename X, typename Y >
FastDelegate(const Y *pthis,
RetType (X::* function_to_bind)( Args... args ) const)
: BaseType(pthis, function_to_bind)
{ }
FastDelegate(RetType (*function_to_bind)( Args... args ))
: BaseType(function_to_bind) { }
void operator = (const BaseType &x) {
*static_cast<BaseType*>(this) = x; }
};
#endif //FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX
////////////////////////////////////////////////////////////////////////////////
// Fast Delegates, part 5:
//
// MakeDelegate() helper function
//
// MakeDelegate(&x, &X::func) returns a fastdelegate of the type
// necessary for calling x.func() with the correct number of arguments.
// This makes it possible to eliminate many typedefs from user code.
//
////////////////////////////////////////////////////////////////////////////////
// Also declare overloads of a MakeDelegate() global function to
// reduce the need for typedefs.
// We need seperate overloads for const and non-const member functions.
// Also, because of the weird rule about the class of derived member function pointers,
// implicit downcasts may need to be applied later to the 'this' pointer.
// That's why two classes (X and Y) appear in the definitions. Y must be implicitly
// castable to X.
template <typename RetType, typename... Args>
FastDelegate<RetType (Args...)> MakeDelegate(RetType (*func)(Args...)) {
return FastDelegate<RetType (Args...)>(func);
}
template <typename RetType, typename X, typename Y, typename... Args>
FastDelegate<RetType (Args...)> MakeDelegate(Y* x, RetType (X::*func)(Args...)) {
return FastDelegate<RetType (Args...)>(x, func);
}
template <typename RetType, typename X, typename Y, typename... Args>
FastDelegate<RetType (Args...)> MakeDelegate(Y* x, RetType (X::*func)(Args...) const) {
return FastDelegate<RetType (Args...)>(x, func);
}
// clean up after ourselves...
#undef FASTDLGT_RETTYPE
} // namespace fastdelegate
#endif // !defined(FASTDELEGATE_HPP)

5
src/AST/ASTVisitor.cs

@ -304,6 +304,11 @@ namespace CppSharp.AST @@ -304,6 +304,11 @@ namespace CppSharp.AST
return true;
}
public virtual bool VisitQualifiedType(QualifiedType type)
{
return type.Type.Visit(this, type.Qualifiers);
}
#endregion
#region Decl Visitors

14
src/AST/ClassExtensions.cs

@ -15,6 +15,20 @@ namespace CppSharp.AST @@ -15,6 +15,20 @@ namespace CppSharp.AST
return @class.Methods.Where(method => method.Name == function.Name);
}
public static bool HasClassInHierarchy(this Class @class, string name)
{
return @class.FindHierarchy(c => c.OriginalName == name || c.Name == name);
}
public static bool FindHierarchy(this Class @class,
Func<Class, bool> func)
{
bool FindHierarchyImpl(Class c, Func<Class, bool> f) => func(c) ||
c.Bases.Any(b => b.IsClass && FindHierarchyImpl(b.Class, f));
return @class.Bases.Any(b => b.IsClass && FindHierarchyImpl(b.Class, func));
}
public static IEnumerable<T> FindHierarchy<T>(this Class @class,
Func<Class, IEnumerable<T>> func)
where T : Declaration

4
src/AST/Declaration.cs

@ -336,6 +336,9 @@ namespace CppSharp.AST @@ -336,6 +336,9 @@ namespace CppSharp.AST
public List<Declaration> Redeclarations { get; } = new List<Declaration>();
// Custom declaration map for custom code generation.
public object DeclMap { get; set; }
protected Declaration()
{
Access = AccessSpecifier.Public;
@ -374,6 +377,7 @@ namespace CppSharp.AST @@ -374,6 +377,7 @@ namespace CppSharp.AST
LineNumberEnd = declaration.LineNumberEnd;
IsImplicit = declaration.IsImplicit;
AssociatedDeclaration = declaration.AssociatedDeclaration;
DeclMap = declaration.DeclMap;
}
public override string ToString()

1
src/AST/FunctionExtensions.cs

@ -83,6 +83,7 @@ namespace CppSharp.AST @@ -83,6 +83,7 @@ namespace CppSharp.AST
public static bool CanOverride(this Method @override, Method method)
{
return (method.OriginalName == @override.OriginalName &&
method.IsVirtual == @override.IsVirtual &&
method.OriginalReturnType.ResolvesTo(@override.OriginalReturnType) &&
method.Parameters.Where(p => p.Kind != ParameterKind.IndirectReturnType).SequenceEqual(
@override.Parameters.Where(p => p.Kind != ParameterKind.IndirectReturnType),

2
src/AST/Method.cs

@ -1,7 +1,5 @@ @@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using CppSharp.AST.Extensions;
namespace CppSharp.AST
{

1
src/AST/TranslationUnit.cs

@ -19,6 +19,7 @@ namespace CppSharp.AST @@ -19,6 +19,7 @@ namespace CppSharp.AST
public TranslationUnit(string file) : this()
{
FilePath = file;
IncludePath = file;
}
/// Contains the macros present in the unit.

16
src/AST/Type.cs

@ -36,6 +36,12 @@ namespace CppSharp.AST @@ -36,6 +36,12 @@ namespace CppSharp.AST
public abstract object Clone();
}
public enum TypeQualifiersMode : byte
{
Default,
Native
}
/// <summary>
/// Represents C++ type qualifiers.
/// </summary>
@ -44,10 +50,11 @@ namespace CppSharp.AST @@ -44,10 +50,11 @@ namespace CppSharp.AST
public bool IsConst;
public bool IsVolatile;
public bool IsRestrict;
public TypeQualifiersMode Mode;
public override int GetHashCode() =>
IsConst.GetHashCode() ^ IsVolatile.GetHashCode() ^
IsRestrict.GetHashCode();
IsRestrict.GetHashCode() ^ Mode.GetHashCode();
}
/// <summary>
@ -68,12 +75,12 @@ namespace CppSharp.AST @@ -68,12 +75,12 @@ namespace CppSharp.AST
Qualifiers = qualifiers;
}
public Type Type { get; set; }
public TypeQualifiers Qualifiers { get; set; }
public Type Type;
public TypeQualifiers Qualifiers;
public T Visit<T>(ITypeVisitor<T> visitor)
{
return Type.Visit(visitor, Qualifiers);
return visitor.VisitQualifiedType(this);
}
public override string ToString()
@ -1287,5 +1294,6 @@ namespace CppSharp.AST @@ -1287,5 +1294,6 @@ namespace CppSharp.AST
T VisitVectorType(VectorType vectorType, TypeQualifiers quals);
T VisitCILType(CILType type, TypeQualifiers quals);
T VisitUnsupportedType(UnsupportedType type, TypeQualifiers quals);
T VisitQualifiedType(QualifiedType type);
}
}

42
src/CLI/CLI.cs

@ -24,12 +24,15 @@ namespace CppSharp @@ -24,12 +24,15 @@ namespace CppSharp
optionSet.Add("o=|output=", "the {PATH} for the generated bindings file (doesn't need the extension since it will depend on the generator)", v => HandleOutputArg(v, errorMessages) );
optionSet.Add("on=|outputnamespace=", "the {NAMESPACE} that will be used for the generated code", on => options.OutputNamespace = on );
optionSet.Add("m=|module=", "the name for the generated {MODULE}", a => { options.OutputFileName = a; });
optionSet.Add("iln=|inputlibraryname=|inputlib=", "the {NAME} of the shared library that contains the symbols of the generated code", iln => options.InputLibraryName = iln );
optionSet.Add("d|debug", "enables debug mode which generates more verbose code to aid debugging", v => options.Debug = true);
optionSet.Add("c|compile", "enables automatic compilation of the generated code", v => options.Compile = true);
optionSet.Add("g=|gen=|generator=", "the {TYPE} of generated code: 'csharp' or 'cli' ('cli' supported only for Windows)", g => { GetGeneratorKind(g, errorMessages); } );
optionSet.Add("p=|platform=", "the {PLATFORM} that the generated code will target: 'win', 'osx' or 'linux'", p => { GetDestinationPlatform(p, errorMessages); } );
optionSet.Add("a=|arch=", "the {ARCHITECTURE} that the generated code will target: 'x86' or 'x64'", a => { GetDestinationArchitecture(a, errorMessages); } );
optionSet.Add("prefix=", "sets a string prefix to the names of generated files", a => { options.Prefix = a; });
optionSet.Add("exceptions", "enables support for C++ exceptions in the parser", v => { options.EnableExceptions = true; });
optionSet.Add("rtti", "enables support for C++ RTTI in the parser", v => { options.EnableRTTI = true; });
@ -101,7 +104,7 @@ namespace CppSharp @@ -101,7 +104,7 @@ namespace CppSharp
if (Directory.Exists(dir))
options.IncludeDirs.Add(dir);
else
errorMessages.Add(string.Format("Directory '{0}' doesn't exist. Ignoring as include directory.", dir));
errorMessages.Add($"Directory '{dir}' doesn't exist. Ignoring as include directory.");
}
static void HandleOutputArg(string arg, List<string> errorMessages)
@ -196,7 +199,7 @@ namespace CppSharp @@ -196,7 +199,7 @@ namespace CppSharp
}
catch (Exception)
{
errorMessages.Add(string.Format("Error while looking for files inside path '{0}'. Ignoring.", path));
errorMessages.Add($"Error while looking for files inside path '{path}'. Ignoring.");
}
}
@ -210,9 +213,18 @@ namespace CppSharp @@ -210,9 +213,18 @@ namespace CppSharp
case "cli":
options.Kind = CppSharp.Generators.GeneratorKind.CLI;
return;
case "c":
options.Kind = CppSharp.Generators.GeneratorKind.C;
return;
case "cpp":
options.Kind = CppSharp.Generators.GeneratorKind.CPlusPlus;
return;
case "qjs":
options.Kind = CppSharp.Generators.GeneratorKind.QuickJS;
return;
}
errorMessages.Add(string.Format("Unknown generator kind: {0}. Defaulting to {1}", generator, options.Kind.ToString()));
errorMessages.Add($"Unknown generator kind: {generator}. Defaulting to {options.Kind}");
}
static void GetDestinationPlatform(string platform, List<string> errorMessages)
@ -230,7 +242,7 @@ namespace CppSharp @@ -230,7 +242,7 @@ namespace CppSharp
return;
}
errorMessages.Add(string.Format("Unknown target platform: {0}. Defaulting to {1}", platform, options.Platform.ToString()));
errorMessages.Add($"Unknown target platform: {platform}. Defaulting to {options.Platform}");
}
static void GetDestinationArchitecture(string architecture, List<string> errorMessages)
@ -245,7 +257,7 @@ namespace CppSharp @@ -245,7 +257,7 @@ namespace CppSharp
return;
}
errorMessages.Add(string.Format("Unknown target architecture: {0}. Defaulting to {1}", architecture, options.Architecture.ToString()));
errorMessages.Add($"Unknown target architecture: {architecture}. Defaulting to {options.Architecture}");
}
static void PrintErrorMessages(List<string> errorMessages)
@ -259,8 +271,8 @@ namespace CppSharp @@ -259,8 +271,8 @@ namespace CppSharp
List<string> errorMessages = new List<string>();
bool helpShown = false;
try
{
//try
//{
if (!ParseCommandLineArgs(args, errorMessages, ref helpShown))
{
PrintErrorMessages(errorMessages);
@ -278,13 +290,13 @@ namespace CppSharp @@ -278,13 +290,13 @@ namespace CppSharp
if (validOptions)
gen.Run();
}
catch (Exception ex)
{
PrintErrorMessages(errorMessages);
Console.Error.WriteLine();
throw ex;
}
}
//catch (Exception ex)
//{
// PrintErrorMessages(errorMessages);
// Console.Error.WriteLine();
// throw ex;
//}
//}
}
}

115
src/CLI/Generator.cs

@ -86,46 +86,25 @@ namespace CppSharp @@ -86,46 +86,25 @@ namespace CppSharp
options.OutputDir = Path.Combine(Directory.GetCurrentDirectory(), "gen");
}
var dir = Path.GetDirectoryName(options.HeaderFiles.First());
var moduleName = new DirectoryInfo(dir).Name;
if (string.IsNullOrEmpty(options.OutputFileName))
options.OutputFileName = moduleName;
if (string.IsNullOrEmpty(options.OutputNamespace))
options.OutputNamespace = moduleName;
if (Platform.IsWindows && options.Platform != TargetPlatform.Windows)
string moduleName;
if (options.HeaderFiles.Count == 1)
{
messages.Add("Cannot create bindings for a platform other that Windows from a Windows host.");
return false;
}
else if (Platform.IsMacOS && options.Platform != TargetPlatform.MacOS)
{
messages.Add("Cannot create bindings for a platform other that macOS from a macOS host.");
return false;
moduleName = Path.GetFileNameWithoutExtension(options.HeaderFiles.First());
}
else if (Platform.IsLinux && options.Platform != TargetPlatform.Linux)
else
{
messages.Add("Cannot create bindings for a platform other that Linux from a Linux host.");
return false;
var dir = Path.GetDirectoryName(options.HeaderFiles.First());
moduleName = new DirectoryInfo(dir).Name;
}
if (options.Platform != TargetPlatform.Windows && options.Kind != GeneratorKind.CSharp)
{
messages.Add("Cannot create bindings for languages other than C# from a non-Windows host.");
return false;
}
if (string.IsNullOrEmpty(options.OutputFileName))
options.OutputFileName = moduleName;
if (options.Platform == TargetPlatform.Linux && options.Architecture != TargetArchitecture.x64)
{
messages.Add("Cannot create bindings for architectures other than x64 for Linux targets.");
return false;
}
if (string.IsNullOrEmpty(options.OutputNamespace))
options.OutputNamespace = moduleName;
SetupTargetTriple();
return true;
}
@ -182,6 +161,10 @@ namespace CppSharp @@ -182,6 +161,10 @@ namespace CppSharp
driverOptions.OutputDir = options.OutputDir;
driverOptions.CheckSymbols = options.CheckSymbols;
driverOptions.Verbose = options.Verbose;
if (!string.IsNullOrEmpty(options.Prefix))
driverOptions.GenerateName = name =>
options.Prefix + name.FileNameWithoutExtension;
}
private void SetupLinuxOptions(ParserOptions parserOptions)
@ -207,55 +190,45 @@ namespace CppSharp @@ -207,55 +190,45 @@ namespace CppSharp
public void Run()
{
StringBuilder messageBuilder = new StringBuilder();
messageBuilder.Append("Generating ");
switch(options.Kind)
{
case GeneratorKind.CLI:
messageBuilder.Append("C++/CLI");
break;
case GeneratorKind.CSharp:
messageBuilder.Append("C#");
break;
}
messageBuilder.Append(" bindings for ");
switch (options.Platform)
{
case TargetPlatform.Linux:
messageBuilder.Append("Linux");
break;
case TargetPlatform.MacOS:
messageBuilder.Append("OSX");
break;
case TargetPlatform.Windows:
messageBuilder.Append("Windows");
break;
}
messageBuilder.Append($"Generating {GetGeneratorKindName(options.Kind)}");
messageBuilder.Append($" bindings for {GetPlatformName(options.Platform)} {options.Architecture}");
messageBuilder.Append(" ");
switch (options.Architecture)
{
case TargetArchitecture.x86:
messageBuilder.Append("x86");
break;
case TargetArchitecture.x64:
messageBuilder.Append("x64");
break;
}
if(options.Cpp11ABI)
if (options.Cpp11ABI)
messageBuilder.Append(" (GCC C++11 ABI)");
messageBuilder.Append("...");
Console.WriteLine(messageBuilder.ToString());
ConsoleDriver.Run(this);
Console.WriteLine();
}
private static string GetPlatformName(TargetPlatform? platform)
{
if (!platform.HasValue)
return string.Empty;
switch (platform.Value)
{
case TargetPlatform.MacOS:
return "macOS";
default:
return platform.ToString();
}
}
private static string GetGeneratorKindName(GeneratorKind kind)
{
switch (kind)
{
case GeneratorKind.CLI:
return "C++/CLI";
case GeneratorKind.CSharp:
return "C#";
default:
return kind.ToString();
}
}
}
}

2
src/CLI/Options.cs

@ -30,6 +30,8 @@ namespace CppSharp @@ -30,6 +30,8 @@ namespace CppSharp
public string OutputFileName { get; set; }
public string InputLibraryName { get; set; }
public string Prefix { get; set; }
public TargetPlatform? Platform { get; set; }

14
src/CppParser/Bootstrap/Bootstrap.cs

@ -117,7 +117,7 @@ namespace CppSharp @@ -117,7 +117,7 @@ namespace CppSharp
ExprClasses = exprSubclassVisitor.Classes;
CodeGeneratorHelpers.CppTypePrinter = new CppTypePrinter(driver.Context)
{ ScopeKind = TypePrintScopeKind.Local };
{ ScopeKind = TypePrintScopeKind.Local };
GenerateStmt(driver.Context);
GenerateExpr(driver.Context);
@ -810,7 +810,7 @@ namespace CppSharp @@ -810,7 +810,7 @@ namespace CppSharp
UnindentAndWriteCloseBrace();
}
WriteLine($"default:");
WriteLineIndent($"throw new System.NotImplementedException(" +
$"{ParamName}.StmtClass.ToString());");
@ -1352,12 +1352,14 @@ namespace CppSharp @@ -1352,12 +1352,14 @@ namespace CppSharp
WriteLine($"_S->{fieldName} = WalkTemplateArgument(S->{methodName}());");
else if (typeName.Contains("QualifiedType"))
WriteLine($"_S->{fieldName} = GetQualifiedType(S->{methodName}());");
else if (fieldName == "value" && @class.Bases.Exists(b => b.Class.Name.Contains("AP"))) {
else if (fieldName == "value" && @class.Bases.Exists(b => b.Class.Name.Contains("AP")))
{
// Use llvm::APInt or llvm::APFloat conversion methods
methodName = property.Type.IsPrimitiveType(PrimitiveType.ULongLong) ?
"getLimitedValue" : "convertToDouble";
WriteLine($"_S->{fieldName} = S->getValue().{methodName}();");
} else
}
else
WriteLine($"_S->{fieldName} = S->{methodName}();");
if (validMethodExists)
@ -1425,7 +1427,7 @@ namespace CppSharp @@ -1425,7 +1427,7 @@ namespace CppSharp
"AST::Expr* Parser::WalkExpression(const clang::Expr* Expr)";
}
class NativeParserCodeGenerator : CCodeGenerator
class NativeParserCodeGenerator : Generators.C.CCodeGenerator
{
internal readonly IEnumerable<Declaration> Declarations;
@ -1793,7 +1795,7 @@ namespace CppSharp @@ -1793,7 +1795,7 @@ namespace CppSharp
if (kind == GeneratorKind.CPlusPlus)
{
if (CCodeGenerator.IsReservedKeyword(name))
if (Generators.C.CCodeGenerator.IsReservedKeyword(name))
name = $"_{name}";
}
else if (kind == GeneratorKind.CSharp)

26
src/Generator/Driver.cs

@ -47,6 +47,8 @@ namespace CppSharp @@ -47,6 +47,8 @@ namespace CppSharp
return new CSharpGenerator(Context);
case GeneratorKind.NAPI:
return new NAPIGenerator(Context);
case GeneratorKind.QuickJS:
return new QuickJSGenerator(Context);
}
throw new NotImplementedException();
@ -108,7 +110,7 @@ namespace CppSharp @@ -108,7 +110,7 @@ namespace CppSharp
break;
case ParserResultKind.FileNotFound:
Diagnostics.Error("File{0} not found: '{1}'",
(files.Count() > 1) ? "s" : "", string.Join(",", files));
(files.Count() > 1) ? "s" : "", string.Join(",", files));
hasParsingErrors = true;
break;
}
@ -345,7 +347,9 @@ namespace CppSharp @@ -345,7 +347,9 @@ namespace CppSharp
var file = Path.Combine(outputPath, fileRelativePath);
File.WriteAllText(file, template.Generate());
output.TranslationUnit.Module.CodeFiles.Add(file);
if (output.TranslationUnit.Module != null)
output.TranslationUnit.Module.CodeFiles.Add(file);
Diagnostics.Message("Generated '{0}'", fileRelativePath);
}
@ -366,13 +370,13 @@ namespace CppSharp @@ -366,13 +370,13 @@ namespace CppSharp
compilerOptions.Append(" /unsafe");
var compilerParameters = new CompilerParameters
{
GenerateExecutable = false,
TreatWarningsAsErrors = false,
OutputAssembly = assemblyFile,
GenerateInMemory = false,
CompilerOptions = compilerOptions.ToString()
};
{
GenerateExecutable = false,
TreatWarningsAsErrors = false,
OutputAssembly = assemblyFile,
GenerateInMemory = false,
CompilerOptions = compilerOptions.ToString()
};
if (module != Options.SystemModule)
compilerParameters.ReferencedAssemblies.Add(
@ -440,7 +444,7 @@ namespace CppSharp @@ -440,7 +444,7 @@ namespace CppSharp
driver.Setup();
if(driver.Options.Verbose)
if (driver.Options.Verbose)
Diagnostics.Level = DiagnosticKind.Debug;
if (!options.Quiet)
@ -480,6 +484,8 @@ namespace CppSharp @@ -480,6 +484,8 @@ namespace CppSharp
{
var outputs = driver.GenerateCode();
library.GenerateCode(driver, outputs);
foreach (var output in outputs)
{
foreach (var pass in driver.Context.GeneratorOutputPasses.Passes)

49
src/Generator/Generator.cs

@ -17,7 +17,8 @@ namespace CppSharp.Generators @@ -17,7 +17,8 @@ namespace CppSharp.Generators
ObjectiveC,
Java,
Swift,
NAPI
NAPI,
QuickJS
}
/// <summary>
@ -80,42 +81,26 @@ namespace CppSharp.Generators @@ -80,42 +81,26 @@ namespace CppSharp.Generators
{
var outputs = new List<GeneratorOutput>();
if (Context.Options.GenerationOutputMode == GenerationOutputMode.FilePerModule ||
Context.Options.GenerateSingleCSharpFile)
var units = Context.ASTContext.TranslationUnits.GetGenerated()
.Where(u => !u.IsSystemHeader).ToList();
foreach (var unit in units)
{
foreach (var module in Context.Options.Modules)
var output = GenerateUnit(unit);
if (output != null)
{
var output = GenerateModule(module);
if (output != null)
{
OnUnitGenerated(output);
outputs.Add(output);
}
outputs.Add(output);
OnUnitGenerated(output);
}
}
else
{
var units = Context.ASTContext.TranslationUnits.GetGenerated()
.Where(u => !u.IsSystemHeader).ToList();
foreach (var unit in units)
{
var output = GenerateUnit(unit);
if (output != null)
{
outputs.Add(output);
OnUnitGenerated(output);
}
}
if (Context.Options.SystemModule != null)
if (Context.Options.SystemModule != null)
{
var output = GenerateModule(Context.Options.SystemModule);
if (output != null)
{
var output = GenerateModule(Context.Options.SystemModule);
if (output != null)
{
OnUnitGenerated(output);
outputs.Add(output);
}
outputs.Add(output);
OnUnitGenerated(output);
}
}
@ -144,7 +129,7 @@ namespace CppSharp.Generators @@ -144,7 +129,7 @@ namespace CppSharp.Generators
public virtual GeneratorOutput GenerateModule(Module module)
{
throw new NotImplementedException();
return null;
}
protected abstract string TypePrinterDelegate(CppSharp.AST.Type type);

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

@ -1,5 +1,4 @@ @@ -1,5 +1,4 @@
using CppSharp.AST;
using CppSharp.AST.Extensions;
using System.Collections.Generic;
using System.Linq;
@ -55,7 +54,7 @@ namespace CppSharp.Generators.C @@ -55,7 +54,7 @@ namespace CppSharp.Generators.C
public string QualifiedIdentifier(Declaration decl)
{
if (!string.IsNullOrEmpty(TranslationUnit.Module.OutputNamespace))
if (!string.IsNullOrEmpty(TranslationUnit.Module?.OutputNamespace))
{
if (string.IsNullOrEmpty(decl.QualifiedName))
return $"{decl.TranslationUnit.Module.OutputNamespace}";
@ -145,8 +144,8 @@ namespace CppSharp.Generators.C @@ -145,8 +144,8 @@ namespace CppSharp.Generators.C
else
Write($"{enumKind} {enumName}");
if (Options.GeneratorKind == GeneratorKind.CPlusPlus ||
Options.GeneratorKind == GeneratorKind.CLI)
if (!(Options.GeneratorKind == GeneratorKind.C ||
Options.GeneratorKind == GeneratorKind.ObjectiveC))
{
var typeName = CTypePrinter.VisitPrimitiveType(
@enum.BuiltinType.Type, new TypeQualifiers());
@ -378,11 +377,10 @@ namespace CppSharp.Generators.C @@ -378,11 +377,10 @@ namespace CppSharp.Generators.C
if (isDeclaration)
{
if (method.IsOverride)
Write(" override");
//if (method.IsPure)
//Write(" = 0");
if (method.IsPure)
Write(" = 0");
else if (method.IsOverride)
Write(" override");
}
}

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

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

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

@ -1,6 +1,7 @@ @@ -1,6 +1,7 @@
using System.Collections.Generic;
using CppSharp.AST;
using CppSharp.Generators.C;
using CppSharp.Passes;
namespace CppSharp.Generators.Cpp
{
@ -8,7 +9,7 @@ namespace CppSharp.Generators.Cpp @@ -8,7 +9,7 @@ namespace CppSharp.Generators.Cpp
/// C++ generator responsible for driving the generation of source and
/// header files.
/// </summary>
public class CppGenerator : Generator
public class CppGenerator : CGenerator
{
private readonly CppTypePrinter typePrinter;
@ -30,7 +31,11 @@ namespace CppSharp.Generators.Cpp @@ -30,7 +31,11 @@ namespace CppSharp.Generators.Cpp
return outputs;
}
public override bool SetupPasses() => true;
public override bool SetupPasses()
{
new FixupPureMethodsPass().VisitASTContext(Context.ASTContext);
return true;
}
public static bool ShouldGenerateClassNativeField(Class @class)
{
@ -45,4 +50,21 @@ namespace CppSharp.Generators.Cpp @@ -45,4 +50,21 @@ namespace CppSharp.Generators.Cpp
return type.Visit(typePrinter).ToString();
}
}
/// <summary>
/// Removes the pureness of virtual abstract methods in C++ classes since
/// the generated classes cannot have virtual pure methods, as they call
/// the original pure method.
/// This lets user code mark some methods as pure if needed, in that case
/// the generator can generate the necessary pure C++ code annotations safely
/// knowing the only pure functions were user-specified.
/// </summary>
public class FixupPureMethodsPass : TranslationUnitPass
{
public override bool VisitMethodDecl(Method method)
{
method.IsPure = false;
return base.VisitMethodDecl(method);
}
}
}

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

@ -19,60 +19,81 @@ namespace CppSharp.Generators.Cpp @@ -19,60 +19,81 @@ namespace CppSharp.Generators.Cpp
CTypePrinter.PushContext(TypePrinterContextKind.Managed);
}
/// <summary>
/// Wether to generate includes or forward references for the native
/// library types.
/// </summary>
public bool GenerateNativeIncludes = true;
public virtual bool ShouldGenerateNamespaces => true;
public override string FileExtension => "h";
public override void Process()
{
GenerateFilePreamble(CommentKind.BCPL);
PushBlock(BlockKind.Includes);
WriteLine("#pragma once");
NewLine();
GenerateIncludes();
// Generate namespace for forward references.
GenerateForwardRefs();
GenerateMain();
PushBlock(BlockKind.Footer);
PopBlock();
}
public virtual void GenerateMain()
{
VisitNamespace(TranslationUnit);
}
public virtual void GenerateIncludes()
{
PushBlock(BlockKind.Includes);
PushBlock(BlockKind.IncludesForwardReferences);
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);
if (GenerateNativeIncludes)
WriteLine("#include <{0}>", TranslationUnit.IncludePath);
// Generate namespace for forward references.
PushBlock(BlockKind.ForwardReferences);
GenerateForwardRefs();
PopBlock(NewLineKind.BeforeNextBlock);
GenerateIncludeForwardRefs(TranslationUnit);
VisitNamespace(TranslationUnit);
PopBlock(NewLineKind.BeforeNextBlock);
PushBlock(BlockKind.Footer);
PopBlock();
PopBlock(NewLineKind.Always);
}
public void GenerateIncludeForwardRefs()
public void GenerateIncludeForwardRefs(TranslationUnit unit)
{
var typeReferenceCollector = new CLITypeReferenceCollector(Context.TypeMaps,
Context.Options);
typeReferenceCollector.Process(TranslationUnit, filterNamespaces: false);
typeReferenceCollector.Process(unit, filterNamespaces: false);
var includes = new SortedSet<string>(StringComparer.InvariantCulture);
foreach (var typeRef in typeReferenceCollector.TypeReferences)
{
if (typeRef.Include.TranslationUnit == TranslationUnit)
if (typeRef.Include.TranslationUnit == unit)
continue;
if (typeRef.Include.File == TranslationUnit.FileName)
if (typeRef.Include.File == unit.FileName)
continue;
var include = typeRef.Include;
var unit = include.TranslationUnit;
var typeRefUnit = include.TranslationUnit;
if (unit != null && !unit.IsDeclared)
if (typeRefUnit != null && !typeRefUnit.IsDeclared)
continue;
if(!string.IsNullOrEmpty(include.File) && include.InHeader)
@ -101,8 +122,10 @@ namespace CppSharp.Generators.Cpp @@ -101,8 +122,10 @@ namespace CppSharp.Generators.Cpp
IEnumerable<CLITypeReference> typeReferences)
{
// Create a new tree of namespaces out of the type references found.
var rootNamespace = new TranslationUnit();
rootNamespace.Module = TranslationUnit.Module;
var rootNamespace = new TranslationUnit
{
Module = TranslationUnit.Module
};
var sortedRefs = typeReferences.ToList();
sortedRefs.Sort((ref1, ref2) =>
@ -137,16 +160,49 @@ namespace CppSharp.Generators.Cpp @@ -137,16 +160,49 @@ namespace CppSharp.Generators.Cpp
return rootNamespace;
}
public void GenerateForwardRefs()
public Namespace ConvertNativeForwardReferencesToNamespaces(
IEnumerable<Declaration> declReferences)
{
var rootNamespace = new TranslationUnit
{
Module = new Module(string.Empty)
};
foreach (var declaration in declReferences)
{
var @namespace = FindCreateNamespace(rootNamespace, declaration);
var typeReference = new CLITypeReference()
{
FowardReference = $"class {declaration.OriginalName};"
};
@namespace.TypeReferences.Add(typeReference);
}
return rootNamespace;
}
public virtual void GenerateForwardRefs()
{
PushBlock(BlockKind.ForwardReferences);
var typeReferenceCollector = new CLITypeReferenceCollector(Context.TypeMaps,
Context.Options);
typeReferenceCollector.Process(TranslationUnit);
if (!GenerateNativeIncludes)
{
var nativeForwardRefs = ConvertNativeForwardReferencesToNamespaces(
typeReferenceCollector.GeneratedDeclarations);
nativeForwardRefs.Visit(this);
}
var typeReferences = typeReferenceCollector.TypeReferences;
var @namespace = ConvertForwardReferencesToNamespaces(typeReferences);
@namespace.Visit(this);
PopBlock(NewLineKind.BeforeNextBlock);
}
public override bool VisitDeclContext(DeclarationContext decl)
@ -188,7 +244,8 @@ namespace CppSharp.Generators.Cpp @@ -188,7 +244,8 @@ namespace CppSharp.Generators.Cpp
{
var isTopLevel = @namespace is TranslationUnit;
var generateNamespace = !isTopLevel ||
!string.IsNullOrEmpty(@namespace.TranslationUnit.Module.OutputNamespace);
!string.IsNullOrEmpty(@namespace.TranslationUnit.Module?.OutputNamespace);
generateNamespace &= ShouldGenerateNamespaces;
if (generateNamespace)
{

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

@ -41,28 +41,38 @@ namespace CppSharp.Generators.Cpp @@ -41,28 +41,38 @@ namespace CppSharp.Generators.Cpp
NewLine();
PopBlock();
VisitNamespace(TranslationUnit);
GenerateMain();
PushBlock(BlockKind.Footer);
PopBlock();
}
public void GenerateForwardReferenceHeaders()
public virtual void GenerateMain()
{
VisitNamespace(TranslationUnit);
}
public virtual void GenerateForwardReferenceHeaders()
{
GenerateForwardReferenceHeaders(TranslationUnit);
}
public virtual void GenerateForwardReferenceHeaders(TranslationUnit unit)
{
PushBlock(BlockKind.IncludesForwardReferences);
var typeReferenceCollector = new CLITypeReferenceCollector(Context.TypeMaps, Context.Options);
typeReferenceCollector.Process(TranslationUnit, filterNamespaces: false);
typeReferenceCollector.Process(unit, filterNamespaces: false);
var includes = new SortedSet<string>(StringComparer.InvariantCulture);
foreach (var typeRef in typeReferenceCollector.TypeReferences)
{
if (typeRef.Include.File == TranslationUnit.FileName)
if (typeRef.Include.File == unit.FileName)
continue;
var include = typeRef.Include;
if(!string.IsNullOrEmpty(include.File) && !include.InHeader)
if (!string.IsNullOrEmpty(include.File) && !include.InHeader)
includes.Add(include.ToString());
}
@ -72,6 +82,7 @@ namespace CppSharp.Generators.Cpp @@ -72,6 +82,7 @@ namespace CppSharp.Generators.Cpp
PopBlock();
}
public override bool VisitDeclContext(DeclarationContext context)
{
PushBlock(BlockKind.Namespace);
@ -118,16 +129,7 @@ namespace CppSharp.Generators.Cpp @@ -118,16 +129,7 @@ namespace CppSharp.Generators.Cpp
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, @class);
VisitDeclContext(@class);
@ -305,8 +307,12 @@ namespace CppSharp.Generators.Cpp @@ -305,8 +307,12 @@ namespace CppSharp.Generators.Cpp
WriteOpenBraceAndIndent();
PushBlock(BlockKind.ConstructorBody, @class);
WriteLine($"{Helpers.InstanceIdentifier} = {ClassCtorInstanceParamIdentifier};");
PopBlock();
UnindentAndWriteCloseBrace();
NewLine();
}
@ -357,6 +363,9 @@ namespace CppSharp.Generators.Cpp @@ -357,6 +363,9 @@ namespace CppSharp.Generators.Cpp
if (!method.IsGenerated || CppHeaders.FunctionIgnored(method))
return false;
if (method.IsPure)
return false;
PushBlock(BlockKind.Method, method);
GenerateMethodSpecifier(method);
@ -370,6 +379,14 @@ namespace CppSharp.Generators.Cpp @@ -370,6 +379,14 @@ namespace CppSharp.Generators.Cpp
PushBlock(BlockKind.MethodBody, method);
if (Context.DeclMaps.FindDeclMap(method, out DeclMap declMap))
{
declMap.Declaration = method;
declMap.DeclarationContext = @class;
declMap.Generate(this);
goto SkipImpl;
}
if (method.IsConstructor && @class.IsRefType)
WriteLine($"{Helpers.OwnsNativeInstanceIdentifier} = true;");
@ -382,10 +399,14 @@ namespace CppSharp.Generators.Cpp @@ -382,10 +399,14 @@ namespace CppSharp.Generators.Cpp
{
if (!@class.IsAbstract)
{
PushBlock(BlockKind.ConstructorBody, @class);
var @params = GenerateFunctionParamsMarshal(method.Parameters, method);
Write($"{Helpers.InstanceIdentifier} = new ::{method.Namespace.QualifiedOriginalName}(");
GenerateFunctionParams(@params);
WriteLine(");");
PopBlock();
}
}
else
@ -516,21 +537,26 @@ namespace CppSharp.Generators.Cpp @@ -516,21 +537,26 @@ namespace CppSharp.Generators.Cpp
if (needsReturn)
{
var ctx = new MarshalContext(Context, CurrentIndentation)
{
ArgName = Helpers.ReturnIdentifier,
ReturnVarName = Helpers.ReturnIdentifier,
ReturnType = function.ReturnType
};
GenerateFunctionCallReturnMarshal(function);
}
}
var marshal = new CppMarshalNativeToManagedPrinter(ctx);
function.ReturnType.Visit(marshal);
public virtual void GenerateFunctionCallReturnMarshal(Function function)
{
var ctx = new MarshalContext(Context, CurrentIndentation)
{
ArgName = Helpers.ReturnIdentifier,
ReturnVarName = Helpers.ReturnIdentifier,
ReturnType = function.ReturnType
};
if (!string.IsNullOrWhiteSpace(marshal.Context.Before))
Write(marshal.Context.Before);
var marshal = new CppMarshalNativeToManagedPrinter(ctx);
function.ReturnType.Visit(marshal);
WriteLine($"return {marshal.Context.Return};");
}
if (!string.IsNullOrWhiteSpace(marshal.Context.Before))
Write(marshal.Context.Before);
WriteLine($"return {marshal.Context.Return};");
}
public static bool IsNativeMethod(Function function)
@ -580,7 +606,7 @@ namespace CppSharp.Generators.Cpp @@ -580,7 +606,7 @@ namespace CppSharp.Generators.Cpp
return marshals;
}
private ParamMarshal GenerateFunctionParamMarshal(Parameter param, int paramIndex,
public virtual ParamMarshal GenerateFunctionParamMarshal(Parameter param, int paramIndex,
Function function = null)
{
var paramMarshal = new ParamMarshal { Name = param.Name, Param = param };
@ -647,9 +673,28 @@ namespace CppSharp.Generators.Cpp @@ -647,9 +673,28 @@ namespace CppSharp.Generators.Cpp
public class OverridesClassGenerator : CCodeGenerator
{
public OverridesClassGenerator(BindingContext context)
public enum GenerationMode
{
Declaration,
Definition
}
HashSet<Method> UniqueMethods;
Class Class;
readonly Func<Method, bool> Filter;
GenerationMode Mode;
public OverridesClassGenerator(BindingContext context,
GenerationMode mode, Func<Method, bool> filter = null)
: base(context)
{
Mode = mode;
Filter = filter;
}
public virtual bool ShouldVisitMethod(Method method)
{
return Filter != null ? Filter(method) : true;
}
public override bool VisitClassDecl(Class @class)
@ -658,9 +703,13 @@ namespace CppSharp.Generators.Cpp @@ -658,9 +703,13 @@ namespace CppSharp.Generators.Cpp
var typeName = @class.Visit(CTypePrinter);
WriteLine($"class _{@class.Name} : public {typeName}");
WriteOpenBraceAndIndent();
WriteLine("{");
WriteLine("public:");
NewLine();
Indent();
var uniqueMethods = new HashSet<Method>();
Class = @class;
UniqueMethods = new HashSet<Method>();
foreach (var component in @class.Layout.Layout.Components)
{
@ -671,7 +720,10 @@ namespace CppSharp.Generators.Cpp @@ -671,7 +720,10 @@ namespace CppSharp.Generators.Cpp
if (!method.IsVirtual || (method.GenerationKind == GenerationKind.None))
continue;
if (!uniqueMethods.Add(method))
if (!UniqueMethods.Add(method))
continue;
if (!ShouldVisitMethod(method))
continue;
method = new Method(component.Method)
@ -682,42 +734,65 @@ namespace CppSharp.Generators.Cpp @@ -682,42 +734,65 @@ namespace CppSharp.Generators.Cpp
if (method.IsConstructor || method.IsDestructor)
continue;
uniqueMethods.Add(method);
UniqueMethods.Add(method);
method.Visit(this);
}
Unindent();
WriteLine("};");
CTypePrinter.PopContext();
Class = null;
UniqueMethods = null;
return true;
}
public override bool VisitMethodDecl(Method method)
{
PushBlock(BlockKind.Method, method);
var isDeclaration = Mode == GenerationMode.Declaration;
GenerateMethodSpecifier(method, isDeclaration ?
MethodSpecifierKind.Declaration : MethodSpecifierKind.Definition);
PushBlock(BlockKind.Method, method);
GenerateMethodSpecifier(method, MethodSpecifierKind.Declaration);
if (isDeclaration)
{
WriteLine(";");
}
else
{
NewLine();
WriteOpenBraceAndIndent();
DeclMap declMap;
if (Context.DeclMaps.FindDeclMap(method, out declMap))
if (Context.DeclMaps.FindDeclMap(method, out DeclMap declMap))
{
declMap.Declaration = method;
declMap.DeclarationContext = @class;
declMap.DeclarationContext = Class;
declMap.Generate(this);
}
var needsReturn = !method.ReturnType.Type.IsPrimitiveType(PrimitiveType.Void);
if (needsReturn)
else
{
var returnType = method.ReturnType.Visit(CTypePrinter);
Write($"{returnType} {Helpers.ReturnIdentifier} = ");
}
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});");
var parameters = string.Join(", ", method.Parameters.Select(p => p.Name));
WriteLine($"this->{method.OriginalName}({parameters});");
if (needsReturn)
WriteLine($"return {Helpers.ReturnIdentifier};");
if (needsReturn)
WriteLine($"return {Helpers.ReturnIdentifier};");
}
UnindentAndWriteCloseBrace();
PopBlock(NewLineKind.BeforeNextBlock);
}
Unindent();
WriteLine("};");
CTypePrinter.PopContext();
PopBlock(NewLineKind.BeforeNextBlock);
return true;
}

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

@ -424,7 +424,7 @@ namespace CppSharp.Generators.C @@ -424,7 +424,7 @@ namespace CppSharp.Generators.C
Parameter oldParam = Parameter;
Parameter = param;
var result = param.Type.Visit(this, param.QualifiedType.Qualifiers);
var result = param.QualifiedType.Visit(this);
Parameter = oldParam;
@ -446,6 +446,19 @@ namespace CppSharp.Generators.C @@ -446,6 +446,19 @@ namespace CppSharp.Generators.C
throw new NotImplementedException();
}
public override TypePrinterResult VisitQualifiedType(QualifiedType type)
{
if (type.Qualifiers.Mode == TypeQualifiersMode.Native)
{
PushContext(TypePrinterContextKind.Native);
var result = base.VisitQualifiedType(type);
PopContext();
return result;
}
return base.VisitQualifiedType(type);
}
public TypePrinterResult GetDeclName(Declaration declaration,
TypePrintScopeKind scope)
{

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

@ -14,6 +14,26 @@ namespace CppSharp.Generators.C @@ -14,6 +14,26 @@ namespace CppSharp.Generators.C
{
}
public override List<GeneratorOutput> Generate()
{
var outputs = base.Generate();
foreach (var module in Context.Options.Modules)
{
if (module == Context.Options.SystemModule)
continue;
var output = GenerateModule(module);
if (output != null)
{
OnUnitGenerated(output);
outputs.Add(output);
}
}
return outputs;
}
public override List<CodeGenerator> Generate(IEnumerable<TranslationUnit> units)
{
var outputs = new List<CodeGenerator>();
@ -21,7 +41,7 @@ namespace CppSharp.Generators.C @@ -21,7 +41,7 @@ namespace CppSharp.Generators.C
var header = new NAPIHeaders(Context, units);
outputs.Add(header);
var source = new CppSources(Context, units);
var source = new NAPISources(Context, units);
outputs.Add(source);
return outputs;
@ -29,7 +49,24 @@ namespace CppSharp.Generators.C @@ -29,7 +49,24 @@ namespace CppSharp.Generators.C
public override GeneratorOutput GenerateModule(Module module)
{
return base.GenerateModule(module);
if (module == Context.Options.SystemModule)
return null;
var moduleGen = new NAPIModule(Context, module);
var output = new GeneratorOutput
{
TranslationUnit = new TranslationUnit
{
FilePath = $"{module.LibraryName}.cpp",
Module = module
},
Outputs = new List<CodeGenerator> { moduleGen }
};
output.Outputs[0].Process();
return output;
}
}
}

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

@ -10,8 +10,8 @@ namespace CppSharp.Generators.Cpp @@ -10,8 +10,8 @@ namespace CppSharp.Generators.Cpp
/// </summary>
public class NAPIModule : CCodeGenerator
{
public NAPIModule(BindingContext context, IEnumerable<TranslationUnit> units)
: base(context, units)
public NAPIModule(BindingContext context, Module module)
: base(context, module.Units.GetGenerated())
{
CTypePrinter.PushContext(TypePrinterContextKind.Managed);
}
@ -22,15 +22,21 @@ namespace CppSharp.Generators.Cpp @@ -22,15 +22,21 @@ namespace CppSharp.Generators.Cpp
{
var include = new CInclude()
{
File = "node_api.h",
File = "node/node_api.h",
Kind = CInclude.IncludeKind.Angled
};
WriteInclude(include);
NewLine();
WriteLine("NAPI_MODULE_INIT()");
WriteOpenBraceAndIndent();
WriteLine("napi_value result;");
WriteLine("NAPI_CALL(env, napi_create_object(env, &result));");
WriteLine("return result;");
UnindentAndWriteCloseBrace();
}
}

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

@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
using System.Collections.Generic;
using CppSharp.AST;
namespace CppSharp.Generators.Cpp
{
/// <summary>
/// Generates Node N-API C/C++ source files.
/// N-API documentation: https://nodejs.org/api/n-api.html
/// </summary>
public class NAPISources : CppSources
{
public NAPISources(BindingContext context, IEnumerable<TranslationUnit> units)
: base(context, units)
{
CTypePrinter.PushContext(TypePrinterContextKind.Managed);
}
public override void Process()
{
base.Process();
}
}
}

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

@ -37,11 +37,14 @@ namespace CppSharp.Generators.CLI @@ -37,11 +37,14 @@ namespace CppSharp.Generators.CLI
get { return typeReferences.Values; }
}
public HashSet<Declaration> GeneratedDeclarations;
public CLITypeReferenceCollector(ITypeMapDatabase typeMapDatabase, DriverOptions driverOptions)
{
TypeMapDatabase = typeMapDatabase;
DriverOptions = driverOptions;
typeReferences = new Dictionary<Declaration, CLITypeReference>();
GeneratedDeclarations = new HashSet<Declaration>();
}
public CLITypeReference GetTypeReference(Declaration decl)
@ -195,6 +198,9 @@ namespace CppSharp.Generators.CLI @@ -195,6 +198,9 @@ namespace CppSharp.Generators.CLI
if (@class.IsIncomplete && @class.CompleteDeclaration != null)
@class = (Class) @class.CompleteDeclaration;
if (@class.TranslationUnit == TranslationUnit)
GeneratedDeclarations.Add(@class);
string keywords;
if (DriverOptions.IsCLIGenerator)
keywords = @class.IsValueType ? "value struct" : "ref class";

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

@ -13,6 +13,29 @@ namespace CppSharp.Generators.CSharp @@ -13,6 +13,29 @@ namespace CppSharp.Generators.CSharp
typePrinter = new CSharpTypePrinter(context);
}
public override List<GeneratorOutput> Generate()
{
if (Context.Options.GenerationOutputMode == GenerationOutputMode.FilePerModule ||
Context.Options.GenerateSingleCSharpFile)
{
var outputs = new List<GeneratorOutput>();
foreach (var module in Context.Options.Modules)
{
var output = GenerateModule(module);
if (output != null)
{
OnUnitGenerated(output);
outputs.Add(output);
}
}
return outputs;
}
return base.Generate();
}
public override List<CodeGenerator> Generate(IEnumerable<TranslationUnit> units)
{
var outputs = new List<CodeGenerator>();

5
src/Generator/Generators/CodeGenerator.cs

@ -524,6 +524,11 @@ namespace CppSharp.Generators @@ -524,6 +524,11 @@ namespace CppSharp.Generators
throw new NotImplementedException();
}
public bool VisitQualifiedType(QualifiedType type)
{
throw new NotImplementedException();
}
public bool VisitStmt(Stmt stmt)
{
throw new NotImplementedException();

5
src/Generator/Generators/TypePrinter.cs

@ -403,6 +403,11 @@ namespace CppSharp.Generators @@ -403,6 +403,11 @@ namespace CppSharp.Generators
throw new NotImplementedException();
}
public virtual TypePrinterResult VisitQualifiedType(QualifiedType type)
{
return type.Type.Visit(this, type.Qualifiers);
}
#endregion
}
}

6
src/Generator/Library.cs

@ -4,6 +4,7 @@ using System.Globalization; @@ -4,6 +4,7 @@ using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
using CppSharp.AST;
using CppSharp.Generators;
using CppSharp.Passes;
namespace CppSharp
@ -33,6 +34,11 @@ namespace CppSharp @@ -33,6 +34,11 @@ namespace CppSharp
/// </summary>
/// <param name="driver"></param>
void SetupPasses(Driver driver);
/// <summary>
/// Generate custom code here.
/// </summary>
void GenerateCode(Driver driver, List<GeneratorOutput> outputs);
}
public static class LibraryHelpers

6
src/Generator/Options.cs

@ -146,6 +146,12 @@ namespace CppSharp @@ -146,6 +146,12 @@ namespace CppSharp
[Obsolete("Use the more general GenerationOutputMode property instead.")]
public bool GenerateSingleCSharpFile { get; set; } = true;
/// <summary>
/// Sets the generation output mode which affects how output files are
/// generated, either as one output file per binding module, or as one
/// output file for each input translation unit.
/// Note: Currently only available for C# generator.
/// </summary>
public GenerationOutputMode GenerationOutputMode { get; set; } =
GenerationOutputMode.FilePerUnit;

1
src/Generator/Passes/CheckDuplicatedNamesPass.cs

@ -210,6 +210,7 @@ namespace CppSharp.Passes @@ -210,6 +210,7 @@ namespace CppSharp.Passes
break;
case GeneratorKind.CPlusPlus:
case GeneratorKind.NAPI:
case GeneratorKind.QuickJS:
typePrinter = new CppTypePrinter(Context);
break;
case GeneratorKind.CLI:

36
src/Generator/Passes/CheckIgnoredDecls.cs

@ -137,8 +137,8 @@ namespace CppSharp.Passes @@ -137,8 +137,8 @@ namespace CppSharp.Passes
public override bool VisitFunctionTemplateDecl(FunctionTemplate decl)
{
if (!base.VisitFunctionTemplateDecl(decl))
return false;
if (!base.VisitFunctionTemplateDecl(decl))
return false;
if (decl.TemplatedFunction.IsDependent && !decl.IsExplicitlyGenerated)
{
@ -383,13 +383,13 @@ namespace CppSharp.Passes @@ -383,13 +383,13 @@ namespace CppSharp.Passes
if (HasInvalidType(variable.Type, variable, out msg))
if (HasInvalidType(variable, out msg))
{
variable.ExplicitlyIgnore();
Diagnostics.Debug("Variable '{0}' was ignored due to {1} type",
variable.Name, msg);
return false;
}
if (HasInvalidType(variable, out msg))
{
variable.ExplicitlyIgnore();
Diagnostics.Debug("Variable '{0}' was ignored due to {1} type",
variable.Name, msg);
return false;
}
return true;
}
@ -420,13 +420,13 @@ namespace CppSharp.Passes @@ -420,13 +420,13 @@ namespace CppSharp.Passes
if (HasInvalidType(param.Type, param, out msg))
if (HasInvalidType(param, out msg))
{
@event.ExplicitlyIgnore();
Diagnostics.Debug("Event '{0}' was ignored due to {1} param",
@event.Name, msg);
return false;
}
if (HasInvalidType(param, out msg))
{
@event.ExplicitlyIgnore();
Diagnostics.Debug("Event '{0}' was ignored due to {1} param",
@event.Name, msg);
return false;
}
}
return true;
@ -451,7 +451,7 @@ namespace CppSharp.Passes @@ -451,7 +451,7 @@ namespace CppSharp.Passes
/// </summary>
private bool HasInvalidType(ITypedDecl decl, out string msg)
{
return HasInvalidType(decl.Type, (Declaration) decl, out msg);
return HasInvalidType(decl.Type, (Declaration)decl, out msg);
}
private bool HasInvalidType(Type type, Declaration decl, out string msg)
@ -503,7 +503,7 @@ namespace CppSharp.Passes @@ -503,7 +503,7 @@ namespace CppSharp.Passes
}
var @class = decl as Class;
if (@class != null && @class.IsOpaque && !@class.IsDependent &&
if (@class != null && @class.IsOpaque && !@class.IsDependent &&
!(@class is ClassTemplateSpecialization))
{
msg = null;

71
src/Generator/Passes/Pass.cs

@ -58,9 +58,78 @@ namespace CppSharp.Passes @@ -58,9 +58,78 @@ namespace CppSharp.Passes
{
public IDiagnostics Log { get; set; }
public virtual void HandleBlock(Block block)
{
switch(block.Kind)
{
case BlockKind.Class:
VisitClass(block);
break;
case BlockKind.Method:
VisitMethod(block);
break;
case BlockKind.Constructor:
VisitConstructor(block);
break;
case BlockKind.ConstructorBody:
VisitConstructorBody(block);
break;
case BlockKind.Namespace:
VisitNamespace(block);
break;
case BlockKind.Includes:
VisitIncludes(block);
break;
}
foreach (var childBlock in block.Blocks)
HandleBlock(childBlock);
}
public virtual void VisitCodeGenerator(CodeGenerator generator)
{
foreach (var block in generator.ActiveBlock.Blocks)
{
HandleBlock(block);
}
}
public virtual void VisitGeneratorOutput(GeneratorOutput output)
{
foreach (var generator in output.Outputs)
{
VisitCodeGenerator(generator);
}
}
public virtual void VisitClass(Block block)
{
}
public virtual void VisitNamespace(Block block)
{
}
public virtual void VisitMethod(Block block)
{
}
public virtual void VisitConstructor(Block block)
{
}
public virtual void VisitConstructorBody(Block block)
{
}
public virtual void VisitIncludes(Block block)
{
}
}
}

10
src/Generator/Passes/RenamePass.cs

@ -263,6 +263,9 @@ namespace CppSharp.Passes @@ -263,6 +263,9 @@ namespace CppSharp.Passes
foreach (var @event in @class.Events)
VisitEvent(@event);
foreach (var @enum in @class.Enums)
VisitEnumDecl(@enum);
return true;
}
@ -452,6 +455,13 @@ namespace CppSharp.Passes @@ -452,6 +455,13 @@ namespace CppSharp.Passes
targets));
}
public static void RemovePrefix(string prefix, Declaration decl,
RenameTargets targets = RenameTargets.Any)
{
var pass = new RegexRenamePass("^" + prefix, string.Empty, targets);
decl.Visit(pass);
}
public static void RenameDeclsCase(this PassBuilder<TranslationUnitPass> builder,
RenameTargets targets, RenameCasePattern pattern)
{

6
src/Generator/Types/DeclMapDatabase.cs

@ -60,6 +60,12 @@ namespace CppSharp.Types @@ -60,6 +60,12 @@ namespace CppSharp.Types
public bool FindDeclMap(Declaration decl, out DeclMap declMap)
{
if (decl.DeclMap != null)
{
declMap = decl.DeclMap as DeclMap;
return true;
}
// Looks up the decl in the cache map.
if (declMaps.ContainsKey(decl))
{

14
src/Generator/Utils/BlockGenerator.cs

@ -23,6 +23,7 @@ namespace CppSharp @@ -23,6 +23,7 @@ namespace CppSharp
Footer,
Usings,
Namespace,
TranslationUnit,
Enum,
EnumItem,
Typedef,
@ -50,6 +51,7 @@ namespace CppSharp @@ -50,6 +51,7 @@ namespace CppSharp
Destructor,
AccessSpecifier,
Fields,
Constructor,
ConstructorBody,
DestructorBody,
FinalizerBody
@ -207,6 +209,12 @@ namespace CppSharp @@ -207,6 +209,12 @@ namespace CppSharp
Text.NeedNewLine();
}
public bool NeedsNewLine
{
get => Text.NeedsNewLine;
set => Text.NeedsNewLine = value;
}
public void ResetNewLine()
{
Text.ResetNewLine();
@ -331,6 +339,12 @@ namespace CppSharp @@ -331,6 +339,12 @@ namespace CppSharp
ActiveBlock.NeedNewLine();
}
public bool NeedsNewLine
{
get => ActiveBlock.NeedsNewLine;
set => ActiveBlock.NeedsNewLine = value;
}
public void ResetNewLine()
{
ActiveBlock.ResetNewLine();

1
src/Generator/Utils/TextGenerator.cs

@ -5,6 +5,7 @@ namespace CppSharp @@ -5,6 +5,7 @@ namespace CppSharp
{
public interface ITextGenerator
{
public bool NeedsNewLine { get; set; }
void Write(string msg, params object[] args);
void WriteLine(string msg, params object[] args);
void WriteLineIndent(string msg, params object[] args);

20
tests/CSharp/CSharp.cs

@ -59,10 +59,10 @@ namespace CppSharp.Tests @@ -59,10 +59,10 @@ namespace CppSharp.Tests
ctx.GenerateEnumFromMacros("MyMacroTest2Enum", "MY_MACRO_TEST2_*");
enumTest.Namespace = new Namespace()
{
Name = "MacroTest",
Namespace = ctx.TranslationUnits.First(u => u.IsValid && !u.IsSystemHeader)
};
{
Name = "MacroTest",
Namespace = ctx.TranslationUnits.First(u => u.IsValid && !u.IsSystemHeader)
};
}
public override void Postprocess(Driver driver, ASTContext ctx)
@ -158,10 +158,10 @@ namespace CppSharp.Tests @@ -158,10 +158,10 @@ namespace CppSharp.Tests
var templateSpecializationType = type as TemplateSpecializationType;
if (templateSpecializationType != null)
return templateSpecializationType.Arguments[0].Type.Type;
var declaration = ((TagType) type).Declaration;
var declaration = ((TagType)type).Declaration;
if (declaration.IsDependent)
return new TagType(((Class) declaration).TemplateParameters[0]);
classTemplateSpecialization = (ClassTemplateSpecialization) declaration;
return new TagType(((Class)declaration).TemplateParameters[0]);
classTemplateSpecialization = (ClassTemplateSpecialization)declaration;
return classTemplateSpecialization.Arguments[0].Type.Type;
}
}
@ -199,7 +199,7 @@ namespace CppSharp.Tests @@ -199,7 +199,7 @@ namespace CppSharp.Tests
{
get
{
var type = (TemplateSpecializationType) Type;
var type = (TemplateSpecializationType)Type;
var pointeeType = type.Arguments[0].Type;
var checker = new TypeIgnoreChecker(TypeMapDatabase);
pointeeType.Visit(checker);
@ -211,7 +211,7 @@ namespace CppSharp.Tests @@ -211,7 +211,7 @@ namespace CppSharp.Tests
{
if (ctx.Kind == TypePrinterContextKind.Native)
{
var type = (TemplateSpecializationType) ctx.Type.Desugar();
var type = (TemplateSpecializationType)ctx.Type.Desugar();
var specialization = type.GetClassTemplateSpecialization();
var typePrinter = new CSharpTypePrinter(null);
typePrinter.PushContext(TypePrinterContextKind.Native);
@ -230,7 +230,7 @@ namespace CppSharp.Tests @@ -230,7 +230,7 @@ namespace CppSharp.Tests
public override void CSharpMarshalToNative(CSharpMarshalContext ctx)
{
// pointless, put just so that the generated code compiles
var type = (TemplateSpecializationType) ctx.Parameter.Type.Desugar();
var type = (TemplateSpecializationType)ctx.Parameter.Type.Desugar();
var specialization = type.GetClassTemplateSpecialization();
var typePrinter = new CSharpTypePrinter(null);
typePrinter.PushContext(TypePrinterContextKind.Native);

Loading…
Cancel
Save