aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWim Lavrijsen <WLavrijsen@lbl.gov>2016-06-27 13:59:51 -0700
committerWim Lavrijsen <WLavrijsen@lbl.gov>2016-06-27 13:59:51 -0700
commitee291ba1216644e0d995e8e8e9d303786ede0ea9 (patch)
tree57560015ba79d70b86394d210776dcfa755c7cc6
parentstart of exchanging reflex by cling (diff)
downloadpypy-ee291ba1216644e0d995e8e8e9d303786ede0ea9.tar.gz
pypy-ee291ba1216644e0d995e8e8e9d303786ede0ea9.tar.bz2
pypy-ee291ba1216644e0d995e8e8e9d303786ede0ea9.zip
From Aditi: first stab at new Cling backend, based off the C++ Cppyy.cxx
-rw-r--r--.hgignore2
-rw-r--r--pypy/module/cppyy/bench/Makefile2
-rw-r--r--pypy/module/cppyy/capi/__init__.py4
-rw-r--r--pypy/module/cppyy/capi/builtin_capi.py3
-rw-r--r--pypy/module/cppyy/capi/cling_capi.py15
-rw-r--r--pypy/module/cppyy/converter.py5
-rw-r--r--pypy/module/cppyy/include/cpp_cppyy.h143
-rw-r--r--pypy/module/cppyy/include/cppyy.h2
-rw-r--r--pypy/module/cppyy/src/callcontext.h101
-rw-r--r--pypy/module/cppyy/src/clingcwrapper.cxx2922
-rw-r--r--pypy/module/cppyy/test/Makefile6
-rw-r--r--pypy/module/cppyy/test/advancedcpp.xml2
-rw-r--r--pypy/module/cppyy/test/advancedcpp2.xml2
-rw-r--r--pypy/module/cppyy/test/stltypes.xml12
-rw-r--r--pypy/module/cppyy/test/test_cppyy.py2
15 files changed, 1518 insertions, 1705 deletions
diff --git a/.hgignore b/.hgignore
index b87f2c389a..e9aa6e807a 100644
--- a/.hgignore
+++ b/.hgignore
@@ -77,3 +77,5 @@ syntax: regexp
^.hypothesis/
^release/
^rpython/_cache$
+
+pypy/module/cppyy/.+/*\.pcm
diff --git a/pypy/module/cppyy/bench/Makefile b/pypy/module/cppyy/bench/Makefile
index f36a456f80..462651ead9 100644
--- a/pypy/module/cppyy/bench/Makefile
+++ b/pypy/module/cppyy/bench/Makefile
@@ -26,4 +26,4 @@ endif
bench02Dict_reflex.so: bench02.h bench02.cxx bench02.xml
$(genreflex) bench02.h $(genreflexflags) --selection=bench02.xml -I$(ROOTSYS)/include
- g++ -o $@ bench02.cxx bench02_rflx.cpp -I$(ROOTSYS)/include -shared -lReflex -lHistPainter `root-config --libs` $(cppflags) $(cppflags2)
+ g++ -o $@ bench02.cxx bench02_rflx.cpp -I$(ROOTSYS)/include -shared -std=c++14 -lHistPainter `root-config --libs` $(cppflags) $(cppflags2)
diff --git a/pypy/module/cppyy/capi/__init__.py b/pypy/module/cppyy/capi/__init__.py
index 3875fe1ff3..8e912f98be 100644
--- a/pypy/module/cppyy/capi/__init__.py
+++ b/pypy/module/cppyy/capi/__init__.py
@@ -9,8 +9,8 @@ from rpython.rtyper.lltypesystem import rffi, lltype
# the selection of the desired backend (default is Reflex).
# choose C-API access method:
-from pypy.module.cppyy.capi.loadable_capi import *
-#from pypy.module.cppyy.capi.builtin_capi import *
+#from pypy.module.cppyy.capi.loadable_capi import *
+from pypy.module.cppyy.capi.builtin_capi import *
from pypy.module.cppyy.capi.capi_types import C_OBJECT,\
C_NULL_TYPE, C_NULL_OBJECT
diff --git a/pypy/module/cppyy/capi/builtin_capi.py b/pypy/module/cppyy/capi/builtin_capi.py
index 2189c9ab2f..02bdc4252c 100644
--- a/pypy/module/cppyy/capi/builtin_capi.py
+++ b/pypy/module/cppyy/capi/builtin_capi.py
@@ -1,7 +1,8 @@
from rpython.rtyper.lltypesystem import rffi, lltype
from rpython.rlib import jit
-import reflex_capi as backend
+import cling_capi as backend
+#import reflex_capi as backend
#import cint_capi as backend
from pypy.module.cppyy.capi.capi_types import C_SCOPE, C_TYPE, C_OBJECT,\
diff --git a/pypy/module/cppyy/capi/cling_capi.py b/pypy/module/cppyy/capi/cling_capi.py
index a6e5c40cb8..2f7a280a17 100644
--- a/pypy/module/cppyy/capi/cling_capi.py
+++ b/pypy/module/cppyy/capi/cling_capi.py
@@ -16,7 +16,8 @@ import commands
if os.environ.get("ROOTSYS"):
if config_stat != 0: # presumably Reflex-only
rootincpath = [os.path.join(os.environ["ROOTSYS"], "interpreter/cling/include"),
- os.path.join(os.environ["ROOTSYS"], "interpreter/llvm/inst/include")]
+ os.path.join(os.environ["ROOTSYS"], "interpreter/llvm/inst/include"),
+ os.path.join(os.environ["ROOTSYS"], "include"),]
rootlibpath = [os.path.join(os.environ["ROOTSYS"], "lib64"), os.path.join(os.environ["ROOTSYS"], "lib")]
else:
rootincpath = [incdir]
@@ -39,13 +40,21 @@ ts_helper = 'auto'
std_string_name = 'std::basic_string<char>'
+# force loading (and exposure) of libCore symbols
+with rffi.scoped_str2charp('libCore.so') as ll_libname:
+ _coredll = rdynload.dlopen(ll_libname, rdynload.RTLD_GLOBAL | rdynload.RTLD_NOW)
+
+# require local translator path to pickup common defs
+from rpython.translator import cdir
+translator_c_dir = py.path.local(cdir)
+
eci = ExternalCompilationInfo(
separate_module_files=[srcpath.join("clingcwrapper.cxx")],
- include_dirs=[incpath] + rootincpath,
+ include_dirs=[incpath, translator_c_dir] + rootincpath,
includes=["clingcwrapper.h"],
library_dirs=rootlibpath,
libraries=["Cling"],
- compile_extra=["-fno-strict-aliasing"],
+ compile_extra=["-fno-strict-aliasing", "-std=c++14"],
use_cpp_linker=True,
)
diff --git a/pypy/module/cppyy/converter.py b/pypy/module/cppyy/converter.py
index 298276ee7a..03a7527b73 100644
--- a/pypy/module/cppyy/converter.py
+++ b/pypy/module/cppyy/converter.py
@@ -735,7 +735,7 @@ def _build_basic_converters():
type_info = (
(rffi.LONG, ("long", "long int")),
- (rffi.LONGLONG, ("long long", "long long int")),
+ (rffi.LONGLONG, ("long long", "long long int", "Long64_t")),
)
for c_type, names in type_info:
@@ -743,6 +743,7 @@ def _build_basic_converters():
_immutable_ = True
def __init__(self, space, default):
self.default = rffi.cast(self.c_type, capi.c_strtoll(space, default))
+
class ConstRefConverter(ConstRefNumericTypeConverterMixin, BasicConverter):
_immutable_ = True
libffitype = jit_libffi.types.pointer
@@ -761,7 +762,7 @@ def _build_basic_converters():
(rffi.USHORT, ("unsigned short", "unsigned short int")),
(rffi.UINT, ("unsigned", "unsigned int")),
(rffi.ULONG, ("unsigned long", "unsigned long int")),
- (rffi.ULONGLONG, ("unsigned long long", "unsigned long long int")),
+ (rffi.ULONGLONG, ("unsigned long long", "unsigned long long int", "ULong64_t")),
)
for c_type, names in type_info:
diff --git a/pypy/module/cppyy/include/cpp_cppyy.h b/pypy/module/cppyy/include/cpp_cppyy.h
new file mode 100644
index 0000000000..619d742d5c
--- /dev/null
+++ b/pypy/module/cppyy/include/cpp_cppyy.h
@@ -0,0 +1,143 @@
+#ifndef PYROOT_CPPYY_H
+#define PYROOT_CPPYY_H
+
+// Standard
+#include <string>
+#include <vector>
+#include <stddef.h>
+
+//ROOT types
+ typedef long Long_t;
+ typedef unsigned long ULong_t;
+ typedef long long Long64_t;
+ typedef unsigned long long ULong64_t;
+ typedef float Float_t;
+ typedef double Double_t;
+ typedef long double LongDouble_t;
+ typedef bool Bool_t;
+ typedef char Char_t;
+ typedef unsigned char UChar_t;
+ typedef short Short_t;
+ typedef unsigned short UShort_t;
+ typedef int Int_t;
+ typedef unsigned int UInt_t;
+
+namespace Cppyy {
+ typedef ptrdiff_t TCppScope_t;
+ typedef TCppScope_t TCppType_t;
+ typedef void* TCppObject_t;
+ typedef ptrdiff_t TCppMethod_t;
+
+ typedef Long_t TCppIndex_t;
+ typedef void* (*TCppMethPtrGetter_t)( TCppObject_t );
+
+// name to opaque C++ scope representation -----------------------------------
+ TCppIndex_t GetNumScopes( TCppScope_t parent );
+ std::string GetScopeName( TCppScope_t parent, TCppIndex_t iscope );
+ std::string ResolveName( const std::string& cppitem_name );
+ TCppScope_t GetScope( const std::string& scope_name );
+ TCppType_t GetTemplate( const std::string& template_name );
+ TCppType_t GetActualClass( TCppType_t klass, TCppObject_t obj );
+ size_t SizeOf( TCppType_t klass );
+
+ Bool_t IsBuiltin( const std::string& type_name );
+ Bool_t IsComplete( const std::string& type_name );
+
+ extern TCppScope_t gGlobalScope; // for fast access
+
+// memory management ---------------------------------------------------------
+ TCppObject_t Allocate( TCppType_t type );
+ void Deallocate( TCppType_t type, TCppObject_t instance );
+ TCppObject_t Construct( TCppType_t type );
+ void Destruct( TCppType_t type, TCppObject_t instance );
+
+// method/function dispatching -----------------------------------------------
+ void CallV( TCppMethod_t method, TCppObject_t self, void* args );
+ UChar_t CallB( TCppMethod_t method, TCppObject_t self, void* args );
+ Char_t CallC( TCppMethod_t method, TCppObject_t self, void* args );
+ Short_t CallH( TCppMethod_t method, TCppObject_t self, void* args );
+ Int_t CallI( TCppMethod_t method, TCppObject_t self, void* args );
+ Long_t CallL( TCppMethod_t method, TCppObject_t self, void* args );
+ Long64_t CallLL( TCppMethod_t method, TCppObject_t self, void* args );
+ Float_t CallF( TCppMethod_t method, TCppObject_t self, void* args );
+ Double_t CallD( TCppMethod_t method, TCppObject_t self, void* args );
+ LongDouble_t CallLD( TCppMethod_t method, TCppObject_t self, void* args );
+ void* CallR( TCppMethod_t method, TCppObject_t self, void* args );
+ Char_t* CallS( TCppMethod_t method, TCppObject_t self, void* args );
+ TCppObject_t CallConstructor( TCppMethod_t method, TCppType_t type, void* args );
+ void CallDestructor( TCppType_t type, TCppObject_t self );
+ TCppObject_t CallO( TCppMethod_t method, TCppObject_t self, void* args, TCppType_t result_type );
+
+ TCppMethPtrGetter_t GetMethPtrGetter( TCppScope_t scope, TCppIndex_t imeth );
+
+// handling of function argument buffer --------------------------------------
+ void* AllocateFunctionArgs( size_t nargs );
+ void DeallocateFunctionArgs( void* args );
+ size_t GetFunctionArgSizeof();
+ size_t GetFunctionArgTypeoffset();
+
+// scope reflection information ----------------------------------------------
+ Bool_t IsNamespace( TCppScope_t scope );
+ Bool_t IsAbstract( TCppType_t type );
+ Bool_t IsEnum( const std::string& type_name );
+
+// class reflection information ----------------------------------------------
+ std::string GetFinalName( TCppType_t type );
+ std::string GetScopedFinalName( TCppType_t type );
+ Bool_t HasComplexHierarchy( TCppType_t type );
+ TCppIndex_t GetNumBases( TCppType_t type );
+ std::string GetBaseName( TCppType_t type, TCppIndex_t ibase );
+ Bool_t IsSubtype( TCppType_t derived, TCppType_t base );
+ void AddSmartPtrType( const std::string& );
+ Bool_t IsSmartPtr( const std::string& );
+
+// calculate offsets between declared and actual type, up-cast: direction > 0; down-cast: direction < 0
+ ptrdiff_t GetBaseOffset(
+ TCppType_t derived, TCppType_t base, TCppObject_t address, int direction, bool rerror = false );
+
+// method/function reflection information ------------------------------------
+ TCppIndex_t GetNumMethods( TCppScope_t scope );
+ TCppIndex_t GetMethodIndexAt( TCppScope_t scope, TCppIndex_t imeth );
+ std::vector< TCppMethod_t > GetMethodsFromName( TCppScope_t scope, const std::string& name );
+
+ TCppMethod_t GetMethod( TCppScope_t scope, TCppIndex_t imeth );
+
+ std::string GetMethodName( TCppMethod_t );
+ std::string GetMethodResultType( TCppMethod_t );
+ TCppIndex_t GetMethodNumArgs( TCppMethod_t );
+ TCppIndex_t GetMethodReqArgs( TCppMethod_t );
+ std::string GetMethodArgName( TCppMethod_t, int iarg );
+ std::string GetMethodArgType( TCppMethod_t, int iarg );
+ std::string GetMethodArgDefault( TCppMethod_t, int iarg );
+ std::string GetMethodSignature( TCppScope_t scope, TCppIndex_t imeth );
+ Bool_t IsConstMethod( TCppMethod_t );
+
+ Bool_t IsMethodTemplate( TCppMethod_t );
+ TCppIndex_t GetMethodNumTemplateArgs( TCppScope_t scope, TCppIndex_t imeth );
+ std::string GetMethodTemplateArgName( TCppScope_t scope, TCppIndex_t imeth, TCppIndex_t iarg );
+
+ TCppIndex_t GetGlobalOperator(
+ TCppType_t scope, TCppType_t lc, TCppScope_t rc, const std::string& op );
+
+// method properties ---------------------------------------------------------
+ Bool_t IsConstructor( TCppMethod_t method );
+ Bool_t IsPublicMethod( TCppMethod_t method );
+ Bool_t IsStaticMethod( TCppMethod_t method );
+
+// data member reflection information ----------------------------------------
+ TCppIndex_t GetNumDatamembers( TCppScope_t scope );
+ std::string GetDatamemberName( TCppScope_t scope, TCppIndex_t idata );
+ std::string GetDatamemberType( TCppScope_t scope, TCppIndex_t idata );
+ ptrdiff_t GetDatamemberOffset( TCppScope_t scope, TCppIndex_t idata );
+ TCppIndex_t GetDatamemberIndex( TCppScope_t scope, const std::string& name );
+
+// data member properties ----------------------------------------------------
+ Bool_t IsPublicData( TCppScope_t scope, TCppIndex_t idata );
+ Bool_t IsStaticData( TCppScope_t scope, TCppIndex_t idata );
+ Bool_t IsConstData( TCppScope_t scope, TCppIndex_t idata );
+ Bool_t IsEnumData( TCppScope_t scope, TCppIndex_t idata );
+ Int_t GetDimensionSize( TCppScope_t scope, TCppIndex_t idata, int dimension );
+
+} // namespace Cppyy
+
+#endif // ifndef PYROOT_CPPYY_H
diff --git a/pypy/module/cppyy/include/cppyy.h b/pypy/module/cppyy/include/cppyy.h
index a91584fbe1..24ed18ee25 100644
--- a/pypy/module/cppyy/include/cppyy.h
+++ b/pypy/module/cppyy/include/cppyy.h
@@ -1,6 +1,8 @@
#ifndef CPPYY_CPPYY
#define CPPYY_CPPYY
+#include "cpp_cppyy.h"
+
#ifdef __cplusplus
struct CPPYY_G__DUMMY_FOR_CINT7 {
#else
diff --git a/pypy/module/cppyy/src/callcontext.h b/pypy/module/cppyy/src/callcontext.h
new file mode 100644
index 0000000000..ea395e2efa
--- /dev/null
+++ b/pypy/module/cppyy/src/callcontext.h
@@ -0,0 +1,101 @@
+#ifndef PYROOT_TCALLCONTEXT_H
+#define PYROOT_TCALLCONTEXT_H
+
+// Standard
+#include <vector>
+
+//Bindings
+#include "cpp_cppyy.h"
+
+//ROOT
+#include "Rtypes.h"
+
+namespace PyROOT {
+
+// general place holder for function parameters
+ struct TParameter {
+ union Value {
+ Bool_t fBool;
+ Short_t fShort;
+ UShort_t fUShort;
+ Int_t fInt;
+ UInt_t fUInt;
+ Long_t fLong;
+ ULong_t fULong;
+ Long64_t fLongLong;
+ ULong64_t fULongLong;
+ Float_t fFloat;
+ Double_t fDouble;
+ LongDouble_t fLongDouble;
+ void* fVoidp;
+ } fValue;
+ void* fRef;
+ char fTypeCode;
+ };
+
+// extra call information
+ struct TCallContext {
+ TCallContext( std::vector< TParameter >::size_type sz = 0 ) : fArgs( sz ), fFlags( 0 ) {}
+
+ enum ECallFlags {
+ kNone = 0,
+ kIsSorted = 1, // if method overload priority determined
+ kIsCreator = 2, // if method creates python-owned objects
+ kIsConstructor = 4, // if method is a C++ constructor
+ kUseHeuristics = 8, // if method applies heuristics memory policy
+ kUseStrict = 16, // if method applies strict memory policy
+ kManageSmartPtr = 32, // if executor should manage smart pointers
+ kReleaseGIL = 64, // if method should release the GIL
+ kFast = 128, // if method should NOT handle signals
+ kSafe = 256 // if method should return on signals
+ };
+
+ // memory handling
+ static ECallFlags sMemoryPolicy;
+ static Bool_t SetMemoryPolicy( ECallFlags e );
+
+ // signal safety
+ static ECallFlags sSignalPolicy;
+ static Bool_t SetSignalPolicy( ECallFlags e );
+
+ // payload
+ std::vector< TParameter > fArgs;
+ UInt_t fFlags;
+ };
+
+ inline Bool_t IsSorted( UInt_t flags ) {
+ return flags & TCallContext::kIsSorted;
+ }
+
+ inline Bool_t IsCreator( UInt_t flags ) {
+ return flags & TCallContext::kIsCreator;
+ }
+
+ inline Bool_t IsConstructor( UInt_t flags ) {
+ return flags & TCallContext::kIsConstructor;
+ }
+
+ inline Bool_t ManagesSmartPtr( TCallContext* ctxt ) {
+ return ctxt->fFlags & TCallContext::kManageSmartPtr;
+ }
+
+ inline Bool_t ReleasesGIL( UInt_t flags ) {
+ return flags & TCallContext::kReleaseGIL;
+ }
+
+ inline Bool_t ReleasesGIL( TCallContext* ctxt ) {
+ return ctxt ? (ctxt->fFlags & TCallContext::kReleaseGIL) : kFALSE;
+ }
+
+ inline Bool_t UseStrictOwnership( TCallContext* ctxt ) {
+ if ( ctxt && (ctxt->fFlags & TCallContext::kUseStrict) )
+ return kTRUE;
+ if ( ctxt && (ctxt->fFlags & TCallContext::kUseHeuristics) )
+ return kFALSE;
+
+ return TCallContext::sMemoryPolicy == TCallContext::kUseStrict;
+ }
+
+} // namespace PyROOT
+
+#endif // !PYROOT_TCALLCONTEXT_H
diff --git a/pypy/module/cppyy/src/clingcwrapper.cxx b/pypy/module/cppyy/src/clingcwrapper.cxx
index 65473e5312..9084d49c9b 100644
--- a/pypy/module/cppyy/src/clingcwrapper.cxx
+++ b/pypy/module/cppyy/src/clingcwrapper.cxx
@@ -1,1810 +1,1364 @@
-#include "cppyy.h"
-#include "clingcwrapper.h"
-
-/*************************************************************************
- * Copyright (C) 1995-2014, the ROOT team. *
- * LICENSE: LGPLv2.1; see http://root.cern.ch/drupal/content/license *
- * CONTRIBUTORS: see http://root.cern.ch/drupal/content/contributors *
- *************************************************************************/
-
-#include <stdint.h>
-
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/Decl.h"
-#include "clang/AST/DeclBase.h"
-#include "clang/AST/DeclCXX.h"
-#include "clang/AST/PrettyPrinter.h"
-#include "clang/AST/Type.h"
-#include "clang/Frontend/CompilerInstance.h"
-#include "clang/Sema/Sema.h"
-
-#include "cling/Interpreter/DynamicLibraryManager.h"
-#include "cling/Interpreter/Interpreter.h"
-#include "cling/Interpreter/LookupHelper.h"
-#include "cling/Interpreter/StoredValueRef.h"
-#include "cling/MetaProcessor/MetaProcessor.h"
-
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ExecutionEngine/GenericValue.h"
-#include "llvm/Support/raw_ostream.h"
-
-#include <iostream>
+// Bindings
+#include "capi.h"
+#include "cpp_cppyy.h"
+#include "callcontext.h"
+
+// ROOT
+#include "TBaseClass.h"
+#include "TClass.h"
+#include "TClassRef.h"
+#include "TClassTable.h"
+#include "TClassEdit.h"
+#include "TCollection.h"
+#include "TDataMember.h"
+#include "TDataType.h"
+#include "TError.h"
+#include "TFunction.h"
+#include "TGlobal.h"
+#include "TInterpreter.h"
+#include "TList.h"
+#include "TMethod.h"
+#include "TMethodArg.h"
+#include "TROOT.h"
+
+// Standard
+#include <assert.h>
#include <map>
-#include <string>
+#include <set>
#include <sstream>
-#include <vector>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
+// temp
+#include <iostream>
+typedef PyROOT::TParameter TParameter;
+// --temp
+
+
+// small number that allows use of stack for argument passing
+const int SMALL_ARGS_N = 8;
+
+// data for life time management ---------------------------------------------
+typedef std::vector< TClassRef > ClassRefs_t;
+static ClassRefs_t g_classrefs( 1 );
+static const ClassRefs_t::size_type GLOBAL_HANDLE = 1;
+
+typedef std::map< std::string, ClassRefs_t::size_type > Name2ClassRefIndex_t;
+static Name2ClassRefIndex_t g_name2classrefidx;
-using namespace clang;
+typedef std::map< Cppyy::TCppMethod_t, CallFunc_t* > Method2CallFunc_t;
+static Method2CallFunc_t g_method2callfunc;
+typedef std::vector< TFunction > GlobalFuncs_t;
+static GlobalFuncs_t g_globalfuncs;
-/* cling initialization --------------------------------------------------- */
+typedef std::vector< TGlobal* > GlobalVars_t;
+static GlobalVars_t g_globalvars;
+
+// data ----------------------------------------------------------------------
+Cppyy::TCppScope_t Cppyy::gGlobalScope = GLOBAL_HANDLE;
+
+// smart pointer types
+static std::set< std::string > gSmartPtrTypes =
+ { "auto_ptr", "shared_ptr", "weak_ptr", "unique_ptr" };
+
+
+// global initialization -----------------------------------------------------
namespace {
-cling::Interpreter* gCppyy_Cling;
-cling::MetaProcessor* gCppyy_MetaProcessor;
+class ApplicationStarter {
+public:
+ ApplicationStarter() {
+ // setup dummy holders for global and std namespaces
+ assert( g_classrefs.size() == GLOBAL_HANDLE );
+ g_name2classrefidx[ "" ] = GLOBAL_HANDLE;
+ g_classrefs.push_back(TClassRef(""));
+ // ROOT ignores std/::std, so point them to the global namespace
+ g_name2classrefidx[ "std" ] = GLOBAL_HANDLE;
+ g_name2classrefidx[ "::std" ] = GLOBAL_HANDLE;
+ // add a dummy global to refer to as null at index 0
+ g_globalvars.push_back( nullptr );
+ }
-struct Cppyy_InitCling { // TODO: check whether ROOT/meta's TCling is linked in
- Cppyy_InitCling() {
- std::vector<std::string> cling_args_storage;
- cling_args_storage.push_back("cling4cppyy");
+ ~ApplicationStarter() {
+ for ( auto ifunc : g_method2callfunc )
+ gInterpreter->CallFunc_Delete( ifunc.second );
+ }
+} _applicationStarter;
- // TODO: get this from env
- cling_args_storage.push_back("-I/home/wlavrijsen/rootdev/root/etc");
+} // unnamed namespace
- std::vector<const char*> interp_args;
- for (std::vector<std::string>::const_iterator iarg = cling_args_storage.begin();
- iarg != cling_args_storage.end(); ++iarg)
- interp_args.push_back(iarg->c_str());
+// local helpers -------------------------------------------------------------
+static inline
+TClassRef& type_from_handle( Cppyy::TCppScope_t scope )
+{
+ assert( (ClassRefs_t::size_type) scope < g_classrefs.size() );
+ return g_classrefs[ (ClassRefs_t::size_type)scope ];
+}
- // TODO: get this from env
- const char* llvm_resource_dir = "/home/wlavrijsen/rootdev/root/etc/cling";
- gCppyy_Cling = new cling::Interpreter(
- interp_args.size(), &(interp_args[0]), llvm_resource_dir);
+// type_from_handle to go here
+static inline
+TFunction* type_get_method( Cppyy::TCppType_t klass, Cppyy::TCppIndex_t idx )
+{
+ TClassRef& cr = type_from_handle( klass );
+ if ( cr.GetClass() )
+ return (TFunction*)cr->GetListOfMethods()->At( idx );
+ assert( klass == (Cppyy::TCppType_t)GLOBAL_HANDLE );
+ return (TFunction*)idx;
+}
- // fInterpreter->installLazyFunctionCreator(llvmLazyFunctionCreator);
+static inline
+Cppyy::TCppScope_t declaring_scope( Cppyy::TCppMethod_t method )
+{
+ TMethod* m = dynamic_cast<TMethod*>( (TFunction*)method );
+ if ( m ) return Cppyy::GetScope( m->GetClass()->GetName() );
+ return (Cppyy::TCppScope_t)GLOBAL_HANDLE;
+}
- {
- // R__LOCKGUARD(gInterpreterMutex);
- gCppyy_Cling->AddIncludePath("/home/wlavrijsen/rootdev/root/etc/cling");
- gCppyy_Cling->AddIncludePath(".");
- }
+static inline
+char* cppstring_to_cstring(const std::string& name) {
+ char* name_char = (char*)malloc(name.size() + 1);
+ strcpy(name_char, name.c_str());
+ return name_char;
+}
- // don't check whether modules' files exist.
- gCppyy_Cling->getCI()->getPreprocessorOpts().DisablePCHValidation = true;
- // Use a stream that doesn't close its file descriptor.
- static llvm::raw_fd_ostream fMPOuts (STDOUT_FILENO, /* ShouldClose */ false);
- gCppyy_MetaProcessor = new cling::MetaProcessor(*gCppyy_Cling, fMPOuts);
+// name to opaque C++ scope representation -----------------------------------
+Cppyy::TCppIndex_t Cppyy::GetNumScopes( TCppScope_t scope )
+{
+ TClassRef& cr = type_from_handle( scope );
+ if ( cr.GetClass() ) return 0; // not supported if not at global scope
+ assert( scope == (TCppScope_t)GLOBAL_HANDLE );
+ return gClassTable->Classes();
+}
- gCppyy_Cling->enableDynamicLookup();
- }
-} _init;
+std::string Cppyy::GetScopeName( TCppScope_t parent, TCppIndex_t iscope )
+{
+// Retrieve the scope name of the scope indexed with iscope in parent.
+ TClassRef& cr = type_from_handle( parent );
+ if ( cr.GetClass() ) return 0; // not supported if not at global scope
+ assert( parent == (TCppScope_t)GLOBAL_HANDLE );
+ std::string name = gClassTable->At( iscope );
+ if ( name.find("::") == std::string::npos )
+ return name;
+ return "";
+}
-typedef std::map<std::string, cppyy_scope_t> NamedHandles_t;
-static NamedHandles_t s_named;
+std::string Cppyy::ResolveName( const std::string& cppitem_name )
+{
+// Fully resolve the given name to the final type name.
+ std::string tclean = TClassEdit::CleanType( cppitem_name.c_str() );
-struct SimpleScope {
- std::vector<FunctionDecl*> m_methods;
- std::vector<Decl*> m_data;
-};
+ TDataType* dt = gROOT->GetType( tclean.c_str() );
+ if ( dt ) return dt->GetFullTypeName();
+ return TClassEdit::ResolveTypedef( tclean.c_str(), true );
+}
-typedef std::map<cppyy_scope_t, SimpleScope*> Scopes_t;
-static Scopes_t s_scopes;
+Cppyy::TCppScope_t Cppyy::GetScope( const std::string& sname )
+{
+ std::string scope_name;
+ if ( sname.find( "std::", 0, 5 ) == 0 )
+ scope_name = sname.substr( 5, std::string::npos );
+ else
+ scope_name = sname;
+
+ scope_name = ResolveName( scope_name );
+ auto icr = g_name2classrefidx.find( scope_name );
+ if ( icr != g_name2classrefidx.end() )
+ return (TCppType_t)icr->second;
+
+ // use TClass directly, to enable auto-loading
+ TClassRef cr( TClass::GetClass( scope_name.c_str(), kTRUE, kTRUE ) );
+ if ( !cr.GetClass() )
+ return (TCppScope_t)NULL;
+
+ // no check for ClassInfo as forward declared classes are okay (fragile)
+
+ ClassRefs_t::size_type sz = g_classrefs.size();
+ g_name2classrefidx[ scope_name ] = sz;
+ g_classrefs.push_back( TClassRef( scope_name.c_str() ) );
+ return (TCppScope_t)sz;
+}
-typedef std::map<cppyy_method_t, CPPYY_Cling_Wrapper_t> Wrappers_t;
-static Wrappers_t s_wrappers;
+Cppyy::TCppType_t Cppyy::GetTemplate( const std::string& /* template_name */ )
+{
+ return (TCppType_t)0;
+}
-} // unnamed namespace
+Cppyy::TCppType_t Cppyy::GetActualClass( TCppType_t klass, TCppObject_t obj )
+{
+ TClassRef& cr = type_from_handle( klass );
+ TClass* clActual = cr->GetActualClass( (void*)obj );
+ if ( clActual && clActual != cr.GetClass() ) {
+ // TODO: lookup through name should not be needed
+ return (TCppType_t)GetScope( clActual->GetName() );
+ }
+ return klass;
+}
+size_t Cppyy::SizeOf( TCppType_t klass )
+{
+ TClassRef& cr = type_from_handle( klass );
+ if ( cr.GetClass() ) return (size_t)cr->Size();
+ return (size_t)0;
+}
-/* local helpers --------------------------------------------------------- */
-static inline void print_error(const std::string& where, const std::string& what) {
- std::cerr << where << ": " << what << std::endl;
+Bool_t Cppyy::IsBuiltin( const std::string& type_name )
+{
+ TDataType* dt = gROOT->GetType( TClassEdit::CleanType( type_name.c_str(), 1 ).c_str() );
+ if ( dt ) return dt->GetType() != kOther_t;
+ return kFALSE;
}
-static inline char* cppstring_to_cstring(const std::string& name) {
- char* name_char = (char*)malloc(name.size() + 1);
- strcpy(name_char, name.c_str());
- return name_char;
+Bool_t Cppyy::IsComplete( const std::string& type_name )
+{
+// verify whether the dictionary of this class is fully available
+ Bool_t b = kFALSE;
+
+ Int_t oldEIL = gErrorIgnoreLevel;
+ gErrorIgnoreLevel = 3000;
+ TClass* klass = TClass::GetClass( TClassEdit::ShortType( type_name.c_str(), 1 ).c_str() );
+ if ( klass && klass->GetClassInfo() ) // works for normal case w/ dict
+ b = gInterpreter->ClassInfo_IsLoaded( klass->GetClassInfo() );
+ else { // special case for forward declared classes
+ ClassInfo_t* ci = gInterpreter->ClassInfo_Factory( type_name.c_str() );
+ if ( ci ) {
+ b = gInterpreter->ClassInfo_IsLoaded( ci );
+ gInterpreter->ClassInfo_Delete( ci ); // we own the fresh class info
+ }
+ }
+ gErrorIgnoreLevel = oldEIL;
+ return b;
+}
+
+// memory management ---------------------------------------------------------
+Cppyy::TCppObject_t Cppyy::Allocate( TCppType_t type )
+{
+ TClassRef& cr = type_from_handle( type );
+ return (TCppObject_t)malloc( cr->Size() );
+}
+
+void Cppyy::Deallocate( TCppType_t /* type */, TCppObject_t instance )
+{
+ free( instance );
+}
+
+Cppyy::TCppObject_t Cppyy::Construct( TCppType_t type )
+{
+ TClassRef& cr = type_from_handle( type );
+ return (TCppObject_t)cr->New();
+}
+
+void Cppyy::Destruct( TCppType_t type, TCppObject_t instance )
+{
+ TClassRef& cr = type_from_handle( type );
+ cr->Destructor( (void*)instance );
+}
+
+
+// method/function dispatching -----------------------------------------------
+static inline ClassInfo_t* GetGlobalNamespaceInfo()
+{
+ static ClassInfo_t* gcl = gInterpreter->ClassInfo_Factory();
+ return gcl;
+}
+
+static CallFunc_t* GetCallFunc( Cppyy::TCppMethod_t method )
+{
+ auto icf = g_method2callfunc.find( method );
+ if ( icf != g_method2callfunc.end() )
+ return icf->second;
+
+ CallFunc_t* callf = nullptr;
+ TFunction* func = (TFunction*)method;
+ std::string callString = "";
+
+// create, if not cached
+ Cppyy::TCppScope_t scope = declaring_scope( method );
+ const TClassRef& klass = type_from_handle( scope );
+ if ( klass.GetClass() || (func && scope == GLOBAL_HANDLE) ) {
+ ClassInfo_t* gcl = klass.GetClass() ? klass->GetClassInfo() : nullptr;
+ if ( ! gcl )
+ gcl = GetGlobalNamespaceInfo();
+
+ TCollection* method_args = func->GetListOfMethodArgs();
+ TIter iarg( method_args );
+
+ TMethodArg* method_arg = 0;
+ while ((method_arg = (TMethodArg*)iarg.Next())) {
+ std::string fullType = method_arg->GetTypeNormalizedName();
+ if ( callString.empty() )
+ callString = fullType;
+ else
+ callString += ", " + fullType;
+ }
+
+ Long_t offset = 0;
+ callf = gInterpreter->CallFunc_Factory();
+
+ gInterpreter->CallFunc_SetFuncProto(
+ callf,
+ gcl,
+ func ? func->GetName() : klass->GetName(),
+ callString.c_str(),
+ func ? (func->Property() & kIsConstMethod) : kFALSE,
+ &offset,
+ ROOT::kExactMatch );
+
+// CLING WORKAROUND -- The number of arguments is not always correct (e.g. when there
+// are default parameters, causing the callString to be wrong and
+// the exact match to fail); or the method may have been inline or
+// be compiler generated. In all those cases the exact match fails,
+// whereas the conversion match sometimes works.
+ if ( ! gInterpreter->CallFunc_IsValid( callf ) ) {
+ gInterpreter->CallFunc_SetFuncProto(
+ callf,
+ gcl,
+ func ? func->GetName() : klass->GetName(),
+ callString.c_str(),
+ func ? (func->Property() & kIsConstMethod) : kFALSE,
+ &offset ); // <- no kExactMatch as that will fail
+ }
+// -- CLING WORKAROUND
+
+ }
+
+ if ( !( callf && gInterpreter->CallFunc_IsValid( callf ) ) ) {
+ // TODO: propagate this error to caller w/o use of Python C-API
+ /*
+ PyErr_Format( PyExc_RuntimeError, "could not resolve %s::%s(%s)",
+ const_cast<TClassRef&>(klass).GetClassName(),
+ func ? func->GetName() : const_cast<TClassRef&>(klass).GetClassName(),
+ callString.c_str() ); */
+ std::cerr << "TODO: report unresolved function error to Python\n";
+ if ( callf ) gInterpreter->CallFunc_Delete( callf );
+ return nullptr;
+ }
+
+ g_method2callfunc[ method ] = callf;
+ return callf;
+}
+
+static inline void copy_args( void* args_, void** vargs ) {
+ std::vector<TParameter>& args = *(std::vector<TParameter>*)args_;
+ for ( std::vector<TParameter>::size_type i = 0; i < args.size(); ++i ) {
+ switch ( args[i].fTypeCode ) {
+ case 'l': /* long */
+ vargs[i] = (void*)&args[i].fValue.fLong;
+ break;
+ case 'f': /* double */
+ vargs[i] = (void*)&args[i].fValue.fFloat;
+ break;
+ case 'd': /* double */
+ vargs[i] = (void*)&args[i].fValue.fDouble;
+ break;
+ case 'D': /* long double */
+ vargs[i] = (void*)&args[i].fValue.fLongDouble;
+ break;
+ case 'k': /* long long */
+ case 'K': /* unsigned long long */
+ case 'U': /* unsigned long */
+ case 'p': /* void* */
+ vargs[i] = (void*)&args[i].fValue.fVoidp;
+ break;
+ case 'V': /* (void*)type& */
+ vargs[i] = args[i].fValue.fVoidp;
+ break;
+ case 'r': /* const type& */
+ vargs[i] = args[i].fRef;
+ break;
+ default:
+ std::cerr << "unknown type code: " << args[i].fTypeCode << std::endl;
+ break;
+ }
+ }
+}
+
+Bool_t FastCall(
+ Cppyy::TCppMethod_t method, void* args_, void* self, void* result )
+{
+ const std::vector<TParameter>& args = *(std::vector<TParameter>*)args_;
+
+ CallFunc_t* callf = GetCallFunc( method );
+ if ( ! callf )
+ return kFALSE;
+
+ TInterpreter::CallFuncIFacePtr_t faceptr = gCling->CallFunc_IFacePtr( callf );
+ if ( faceptr.fKind == TInterpreter::CallFuncIFacePtr_t::kGeneric ) {
+ if ( args.size() <= SMALL_ARGS_N ) {
+ void* smallbuf[SMALL_ARGS_N];
+ copy_args( args_, smallbuf );
+ faceptr.fGeneric( self, args.size(), smallbuf, result );
+ } else {
+ std::vector<void*> buf( args.size() );
+ copy_args( args_, buf.data() );
+ faceptr.fGeneric( self, args.size(), buf.data(), result );
+ }
+ return kTRUE;
+ }
+
+ if ( faceptr.fKind == TInterpreter::CallFuncIFacePtr_t::kCtor ) {
+ if ( args.size() <= SMALL_ARGS_N ) {
+ void* smallbuf[SMALL_ARGS_N];
+ copy_args( args_, (void**)smallbuf );
+ faceptr.fCtor( (void**)smallbuf, result, args.size() );
+ } else {
+ std::vector<void*> buf( args.size() );
+ copy_args( args_, buf.data() );
+ faceptr.fCtor( buf.data(), result, args.size() );
+ }
+ return kTRUE;
+ }
+
+ if ( faceptr.fKind == TInterpreter::CallFuncIFacePtr_t::kDtor ) {
+ std::cerr << " DESTRUCTOR NOT IMPLEMENTED YET! " << std::endl;
+ return kFALSE;
+ }
+
+ return kFALSE;
+}
+
+template< typename T >
+static inline T CallT( Cppyy::TCppMethod_t method, Cppyy::TCppObject_t self, void* args )
+{
+ T t{};
+ if ( FastCall( method, args, (void*)self, &t ) )
+ return t;
+ return (T)-1;
+}
+
+#define CPPYY_IMP_CALL( typecode, rtype ) \
+rtype Cppyy::Call##typecode( TCppMethod_t method, TCppObject_t self, void* args )\
+{ \
+ return CallT< rtype >( method, self, args ); \
+}
+
+void Cppyy::CallV( TCppMethod_t method, TCppObject_t self, void* args )
+{
+ if ( ! FastCall( method, args, (void*)self, nullptr ) )
+ return /* TODO ... report error */;
+}
+
+CPPYY_IMP_CALL( B, UChar_t )
+CPPYY_IMP_CALL( C, Char_t )
+CPPYY_IMP_CALL( H, Short_t )
+CPPYY_IMP_CALL( I, Int_t )
+CPPYY_IMP_CALL( L, Long_t )
+CPPYY_IMP_CALL( LL, Long64_t )
+CPPYY_IMP_CALL( F, Float_t )
+CPPYY_IMP_CALL( D, Double_t )
+CPPYY_IMP_CALL( LD, LongDouble_t )
+
+void* Cppyy::CallR( TCppMethod_t method, TCppObject_t self, void* args )
+{
+ void* r = nullptr;
+ if ( FastCall( method, args, (void*)self, &r ) )
+ return r;
+ return nullptr;
+}
+
+Char_t* Cppyy::CallS( TCppMethod_t method, TCppObject_t self, void* args )
+{
+ Char_t* s = nullptr;
+ if ( FastCall( method, args, (void*)self, &s ) )
+ return s;
+ return nullptr;
+}
+
+Cppyy::TCppObject_t Cppyy::CallConstructor(
+ TCppMethod_t method, TCppType_t /* klass */, void* args ) {
+ void* obj = nullptr;
+ if ( FastCall( method, args, nullptr, &obj ) )
+ return (TCppObject_t)obj;
+ return (TCppObject_t)0;
+}
+
+void Cppyy::CallDestructor( TCppType_t type, TCppObject_t self )
+{
+ TClassRef& cr = type_from_handle( type );
+ cr->Destructor( (void*)self, kTRUE );
+}
+
+Cppyy::TCppObject_t Cppyy::CallO( TCppMethod_t method,
+ TCppObject_t self, void* args, TCppType_t result_type )
+{
+ TClassRef& cr = type_from_handle( result_type );
+ void* obj = malloc( cr->Size() );
+ if ( FastCall( method, args, self, obj ) )
+ return (TCppObject_t)obj;
+ return (TCppObject_t)0;
+}
+
+Cppyy::TCppMethPtrGetter_t Cppyy::GetMethPtrGetter(
+ TCppScope_t /* scope */, TCppIndex_t /* imeth */ )
+{
+ return (TCppMethPtrGetter_t)0;
+}
+
+
+// handling of function argument buffer --------------------------------------
+void* Cppyy::AllocateFunctionArgs( size_t nargs )
+{
+ return new TParameter[nargs];
+}
+
+void Cppyy::DeallocateFunctionArgs( void* args )
+{
+ delete [] (TParameter*)args;
+}
+
+size_t Cppyy::GetFunctionArgSizeof()
+{
+ return sizeof( TParameter );
+}
+
+size_t Cppyy::GetFunctionArgTypeoffset()
+{
+ return offsetof( TParameter, fTypeCode );
+}
+
+
+// scope reflection information ----------------------------------------------
+Bool_t Cppyy::IsNamespace( TCppScope_t scope ) {
+// Test if this scope represents a namespace.
+ TClassRef& cr = type_from_handle( scope );
+ if ( cr.GetClass() )
+ return cr->Property() & kIsNamespace;
+ return kFALSE;
+}
+
+Bool_t Cppyy::IsAbstract( TCppType_t klass ) {
+// Test if this type may not be instantiated.
+ TClassRef& cr = type_from_handle( klass );
+ if ( cr.GetClass() )
+ return cr->Property() & kIsAbstract;
+ return kFALSE;
+}
+
+Bool_t Cppyy::IsEnum( const std::string& type_name ) {
+ return gInterpreter->ClassInfo_IsEnum( type_name.c_str() );
+}
+
+
+// class reflection information ----------------------------------------------
+std::string Cppyy::GetFinalName( TCppType_t klass )
+{
+ if ( klass == GLOBAL_HANDLE ) // due to CLING WORKAROUND in InitConverters_
+ return "";
+ // TODO: either this or GetScopedFinalName is wrong
+ TClassRef& cr = type_from_handle( klass );
+ return cr->GetName();
+}
+
+std::string Cppyy::GetScopedFinalName( TCppType_t klass )
+{
+ // TODO: either this or GetFinalName is wrong
+ TClassRef& cr = type_from_handle( klass );
+ return cr->GetName();
+}
+
+Bool_t Cppyy::HasComplexHierarchy( TCppType_t /* handle */ )
+{
+// Always TRUE for now (pre-empts certain optimizations).
+ return kTRUE;
+}
+
+Cppyy::TCppIndex_t Cppyy::GetNumBases( TCppType_t klass )
+{
+// Get the total number of base classes that this class has.
+ TClassRef& cr = type_from_handle( klass );
+ if ( cr.GetClass() && cr->GetListOfBases() != 0 )
+ return cr->GetListOfBases()->GetSize();
+ return 0;
+}
+
+std::string Cppyy::GetBaseName( TCppType_t klass, TCppIndex_t ibase )
+{
+ TClassRef& cr = type_from_handle( klass );
+ return ((TBaseClass*)cr->GetListOfBases()->At( ibase ))->GetName();
+}
+
+Bool_t Cppyy::IsSubtype( TCppType_t derived, TCppType_t base )
+{
+ if ( derived == base )
+ return kTRUE;
+ TClassRef& derived_type = type_from_handle( derived );
+ TClassRef& base_type = type_from_handle( base );
+ return derived_type->GetBaseClass( base_type ) != 0;
+}
+
+void Cppyy::AddSmartPtrType( const std::string& type_name ) {
+ gSmartPtrTypes.insert( ResolveName( type_name ) );
+}
+
+Bool_t Cppyy::IsSmartPtr( const std::string& type_name ) {
+// checks if typename denotes a smart pointer
+// TODO: perhaps make this stricter?
+ const std::string& real_name = ResolveName( type_name );
+ return gSmartPtrTypes.find(
+ real_name.substr( 0,real_name.find( "<" ) ) ) != gSmartPtrTypes.end();
+}
+
+// type offsets --------------------------------------------------------------
+ptrdiff_t Cppyy::GetBaseOffset( TCppType_t derived, TCppType_t base,
+ TCppObject_t address, int direction, bool rerror )
+{
+// calculate offsets between declared and actual type, up-cast: direction > 0; down-cast: direction < 0
+ if ( derived == base || !(base && derived) )
+ return (ptrdiff_t)0;
+
+ TClassRef& cd = type_from_handle( derived );
+ TClassRef& cb = type_from_handle( base );
+
+ if ( !cd.GetClass() || !cb.GetClass() )
+ return (ptrdiff_t)0;
+
+ Long_t offset = -1;
+ if ( ! (cd->GetClassInfo() && cb->GetClassInfo()) ) { // gInterpreter requirement
+ // would like to warn, but can't quite determine error from intentional
+ // hiding by developers, so only cover the case where we really should have
+ // had a class info, but apparently don't:
+ if ( cd->IsLoaded() ) {
+ // warn to allow diagnostics
+ std::ostringstream msg;
+ msg << "failed offset calculation between " << cb->GetName() << " and " << cd->GetName();
+ // TODO: propagate this warning to caller w/o use of Python C-API
+ // PyErr_Warn( PyExc_RuntimeWarning, const_cast<char*>( msg.str().c_str() ) );
+ std::cerr << "Warning: " << msg << '\n';
+ }
+
+ // return -1 to signal caller NOT to apply offset
+ return rerror ? (ptrdiff_t)offset : 0;
+ }
+
+ offset = gInterpreter->ClassInfo_GetBaseOffset(
+ cd->GetClassInfo(), cb->GetClassInfo(), (void*)address, direction > 0 );
+ if ( offset == -1 ) // Cling error, treat silently
+ return rerror ? (ptrdiff_t)offset : 0;
+
+ return (ptrdiff_t)(direction < 0 ? -offset : offset);
+}
+
+
+// method/function reflection information ------------------------------------
+Cppyy::TCppIndex_t Cppyy::GetNumMethods( TCppScope_t scope )
+{
+ TClassRef& cr = type_from_handle( scope );
+ if ( cr.GetClass() && cr->GetListOfMethods() ) {
+ Cppyy::TCppIndex_t nMethods = (TCppIndex_t)cr->GetListOfMethods()->GetSize();
+ if ( nMethods == (TCppIndex_t)0 ) {
+ std::string clName = GetScopedFinalName( scope );
+ if ( clName.find( '<' ) != std::string::npos ) {
+ // chicken-and-egg problem: TClass does not know about methods until instantiation: force it
+ if ( TClass::GetClass( ("std::" + clName).c_str() ) )
+ clName = "std::" + clName;
+ std::ostringstream stmt;
+ stmt << "template class " << clName << ";";
+ gInterpreter->Declare( stmt.str().c_str() );
+ // now reload the methods
+ return (TCppIndex_t)cr->GetListOfMethods( kTRUE )->GetSize();
+ }
+ }
+ return nMethods;
+ } else if ( scope == (TCppScope_t)GLOBAL_HANDLE ) {
+ // enforce lazines by denying the existence of methods
+ return (TCppIndex_t)0;
+ }
+ return (TCppIndex_t)0;
+}
+
+Cppyy::TCppIndex_t Cppyy::GetMethodIndexAt( TCppScope_t scope, TCppIndex_t imeth)
+{
+ TClassRef& cr = type_from_handle (scope);
+ if (cr.GetClass())
+ return (TCppIndex_t)imeth;
+ assert(handle == (TCppType_t)GLOBAL_HANDLE);
+ return (TCppIndex_t)&g_globalfuncs[imeth];
+}
+
+std::vector< Cppyy::TCppMethod_t > Cppyy::GetMethodsFromName(
+ TCppScope_t scope, const std::string& name )
+{
+// TODO: this method assumes that the call for this name is made only
+// once, and thus there is no need to store the results of the search
+// in g_globalfuncs ... probably true, but needs verification
+ std::vector< TCppMethod_t > methods;
+ if ( scope == GLOBAL_HANDLE ) {
+ TCollection* funcs = gROOT->GetListOfGlobalFunctions( kTRUE );
+ g_globalfuncs.reserve(funcs->GetSize());
+
+ TIter ifunc(funcs);
+
+ TFunction* func = 0;
+ while ( (func = (TFunction*)ifunc.Next()) ) {
+ // cover not only direct matches, but also template matches
+ std::string fn = func->GetName();
+ if ( fn.rfind( name, 0 ) == 0 ) {
+ // either match exactly, or match the name as template
+ if ( (name.size() == fn.size()) ||
+ (name.size() < fn.size() && fn[name.size()] == '<') ) {
+ methods.push_back( (TCppMethod_t)func );
+ }
+ }
+ }
+ } else {
+ TClassRef& cr = type_from_handle( scope );
+ if ( cr.GetClass() ) {
+ // todo: handle overloads
+ TMethod* m = cr->GetMethodAny( name.c_str() );
+ if ( m ) methods.push_back( (TCppMethod_t)m );
+ }
+ }
+
+ return methods;
+}
+
+Cppyy::TCppMethod_t Cppyy::GetMethod( TCppScope_t scope, TCppIndex_t imeth )
+{
+ TFunction* f = type_get_method( scope, imeth );
+ return (Cppyy::TCppMethod_t)f;
+}
+
+std::string Cppyy::GetMethodName( TCppMethod_t method )
+{
+ if ( method ) {
+ std::string name = ((TFunction*)method)->GetName();
+ //if ( IsMethodTemplate( method ) )
+ // return name.substr( 0, name.find('<') );
+ return name;
+ }
+ return "<unknown>";
+}
+
+std::string Cppyy::GetMethodResultType( TCppMethod_t method )
+{
+ if ( method ) {
+ TFunction* f = (TFunction*)method;
+ if ( f->ExtraProperty() & kIsConstructor )
+ return "constructor";
+ return f->GetReturnTypeNormalizedName();
+ }
+ return "<unknown>";
+}
+
+Cppyy::TCppIndex_t Cppyy::GetMethodNumArgs( TCppMethod_t method )
+{
+ if ( method )
+ return ((TFunction*)method)->GetNargs();
+ return 0;
+}
+
+Cppyy::TCppIndex_t Cppyy::GetMethodReqArgs( TCppMethod_t method )
+{
+ if ( method ) {
+ TFunction* f = (TFunction*)method;
+ return (TCppIndex_t)(f->GetNargs() - f->GetNargsOpt());
+ }
+ return (TCppIndex_t)0;
+}
+
+std::string Cppyy::GetMethodArgName( TCppMethod_t method, int iarg )
+{
+ if ( method ) {
+ TFunction* f = (TFunction*)method;
+ TMethodArg* arg = (TMethodArg*)f->GetListOfMethodArgs()->At( iarg );
+ return arg->GetName();
+ }
+ return "<unknown>";
+}
+
+std::string Cppyy::GetMethodArgType( TCppMethod_t method, int iarg )
+{
+ if ( method ) {
+ TFunction* f = (TFunction*)method;
+ TMethodArg* arg = (TMethodArg*)f->GetListOfMethodArgs()->At( iarg );
+ return arg->GetTypeNormalizedName();
+ }
+ return "<unknown>";
+}
+
+std::string Cppyy::GetMethodArgDefault( TCppMethod_t method, int iarg )
+{
+ if ( method ) {
+ TFunction* f = (TFunction*)method;
+ TMethodArg* arg = (TMethodArg*)f->GetListOfMethodArgs()->At( iarg );
+ const char* def = arg->GetDefault();
+ if ( def )
+ return def;
+ }
+
+ return "";
+}
+
+std::string Cppyy::GetMethodSignature( TCppScope_t /* scope */, TCppIndex_t /* imeth */ )
+{
+ return "<unknown>";
+}
+
+Bool_t Cppyy::IsConstMethod( TCppMethod_t method )
+{
+ if ( method ) {
+ TFunction* f = (TFunction*)method;
+ return f->Property() & kIsConstMethod;
+ }
+ return kFALSE;
+}
+
+
+Bool_t Cppyy::IsMethodTemplate( TCppMethod_t method )
+{
+ if ( method ) {
+ TFunction* f = (TFunction*)method;
+ std::string name = f->GetName();
+ return (name[name.size()-1] == '>') && (name.find('<') != std::string::npos);
+ }
+ return kFALSE;
+}
+
+Cppyy::TCppIndex_t Cppyy::GetMethodNumTemplateArgs(
+ TCppScope_t /* scope */, TCppIndex_t /* imeth */ )
+{
+ return (TCppIndex_t)0;
+}
+
+std::string Cppyy::GetMethodTemplateArgName(
+ TCppScope_t /* scope */, TCppIndex_t /* imeth */, TCppIndex_t /* iarg */ )
+{
+ return "<unknown>";
+}
+
+Cppyy::TCppIndex_t Cppyy::GetGlobalOperator(
+ TCppScope_t /* scope */, TCppType_t /* lc */, TCppType_t /* rc */, const std::string& /* op */ )
+{
+ return (TCppIndex_t)0;
+}
+
+// method properties ---------------------------------------------------------
+Bool_t Cppyy::IsConstructor( TCppMethod_t method )
+{
+ if ( method ) {
+ TFunction* f = (TFunction*)method;
+ return f->ExtraProperty() & kIsConstructor;
+ }
+ return kFALSE;
+}
+
+Bool_t Cppyy::IsPublicMethod( TCppMethod_t method )
+{
+ if ( method ) {
+ TFunction* f = (TFunction*)method;
+ return f->Property() & kIsPublic;
+ }
+ return kFALSE;
+}
+
+Bool_t Cppyy::IsStaticMethod( TCppMethod_t method )
+{
+ if ( method ) {
+ TFunction* f = (TFunction*)method;
+ return f->Property() & kIsStatic;
+ }
+ return kFALSE;
}
-static inline SimpleScope* scope_from_handle(cppyy_type_t handle) {
- return s_scopes[(cppyy_scope_t)handle];
+// data member reflection information ----------------------------------------
+Cppyy::TCppIndex_t Cppyy::GetNumDatamembers( TCppScope_t scope )
+{
+ TClassRef& cr = type_from_handle( scope );
+ if ( cr.GetClass() && cr->GetListOfDataMembers() )
+ return cr->GetListOfDataMembers()->GetSize();
+ else if ( scope == (TCppScope_t)GLOBAL_HANDLE ) {
+ std::cerr << " global data should be retrieved lazily " << std::endl;
+ TCollection* vars = gROOT->GetListOfGlobals( kTRUE );
+ if ( g_globalvars.size() != (GlobalVars_t::size_type)vars->GetSize() ) {
+ g_globalvars.clear();
+ g_globalvars.reserve(vars->GetSize());
+
+ TIter ivar(vars);
+
+ TGlobal* var = 0;
+ while ( (var = (TGlobal*)ivar.Next()) )
+ g_globalvars.push_back( var );
+ }
+ return (TCppIndex_t)g_globalvars.size();
+ }
+ return (TCppIndex_t)0;
}
-static inline std::string qualtype_to_string(const QualType& qt, const ASTContext& atx) {
- std::string result;
+std::string Cppyy::GetDatamemberName( TCppScope_t scope, TCppIndex_t idata )
+{
+ TClassRef& cr = type_from_handle( scope );
+ if (cr.GetClass()) {
+ TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At( idata );
+ return m->GetName();
+ }
+ assert( scope == (TCppScope_t)GLOBAL_HANDLE );
+ TGlobal* gbl = g_globalvars[ idata ];
+ return gbl->GetName();
+}
- PrintingPolicy policy(atx.getPrintingPolicy());
- policy.SuppressTagKeyword = true; // no class or struct keyword
- policy.SuppressScope = true; // force scope from a clang::ElaboratedType
- policy.AnonymousTagLocations = false; // no file name + line number for anonymous types
- // The scope suppression is required for getting rid of the anonymous part of the name
- // of a class defined in an anonymous namespace.
-
- qt.getAsStringInternal(result, policy);
- return result;
+std::string Cppyy::GetDatamemberType( TCppScope_t scope, TCppIndex_t idata )
+{
+ if ( scope == GLOBAL_HANDLE ) {
+ TGlobal* gbl = g_globalvars[ idata ];
+ std::string fullType = gbl->GetFullTypeName();
+ if ( fullType[fullType.size()-1] == '*' && \
+ fullType.find( "char", 0, 4 ) == std::string::npos )
+ fullType.append( "*" );
+ else if ( (int)gbl->GetArrayDim() > 1 )
+ fullType.append( "*" );
+ else if ( (int)gbl->GetArrayDim() == 1 ) {
+ std::ostringstream s;
+ s << '[' << gbl->GetMaxIndex( 0 ) << ']' << std::ends;
+ fullType.append( s.str() );
+ }
+ return fullType;
+ }
+
+ TClassRef& cr = type_from_handle( scope );
+ if ( cr.GetClass() ) {
+ TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At( idata );
+ std::string fullType = m->GetTrueTypeName();
+ if ( (int)m->GetArrayDim() > 1 || (!m->IsBasic() && m->IsaPointer()) )
+ fullType.append( "*" );
+ else if ( (int)m->GetArrayDim() == 1 ) {
+ std::ostringstream s;
+ s << '[' << m->GetMaxIndex( 0 ) << ']' << std::ends;
+ fullType.append( s.str() );
+ }
+ return fullType;
+ }
+
+ return "<unknown>";
}
-static inline std::vector<void*> build_args(int nargs, void* args) {
- std::vector<void*> arguments;
- arguments.reserve(nargs);
- for (int i = 0; i < nargs; ++i) {
- char tc = ((CPPYY_G__value*)args)[i].type;
- if (tc != 'a' && tc != 'o')
- arguments.push_back(&((CPPYY_G__value*)args)[i]);
- else
- arguments.push_back((void*)(*(long*)&((CPPYY_G__value*)args)[i]));
- }
- return arguments;
+ptrdiff_t Cppyy::GetDatamemberOffset( TCppScope_t scope, TCppIndex_t idata )
+{
+ if ( scope == GLOBAL_HANDLE ) {
+ TGlobal* gbl = g_globalvars[ idata ];
+ return (ptrdiff_t)gbl->GetAddress();
+ }
+
+ TClassRef& cr = type_from_handle( scope );
+ if ( cr.GetClass() ) {
+ TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At( idata );
+ return (ptrdiff_t)m->GetOffsetCint(); // yes, CINT ...
+ }
+
+ return (ptrdiff_t)0;
+}
+
+Cppyy::TCppIndex_t Cppyy::GetDatamemberIndex( TCppScope_t scope, const std::string& name )
+{
+ if ( scope == GLOBAL_HANDLE ) {
+ TGlobal* gb = (TGlobal*)gROOT->GetListOfGlobals( kTRUE )->FindObject( name.c_str() );
+ if ( gb && gb->GetAddress() && gb->GetAddress() != (void*)-1 ) {
+ g_globalvars.push_back( gb );
+ return g_globalvars.size() - 1;
+ }
+
+ } else {
+ TClassRef& cr = type_from_handle( scope );
+ if ( cr.GetClass() ) {
+ TDataMember* dm =
+ (TDataMember*)cr->GetListOfDataMembers()->FindObject( name.c_str() );
+ // TODO: turning this into an index is silly ...
+ if ( dm ) return (TCppIndex_t)cr->GetListOfDataMembers()->IndexOf( dm );
+ }
+ }
+
+ return (TCppIndex_t)-1;
}
+// data member properties ----------------------------------------------------
+Bool_t Cppyy::IsPublicData( TCppScope_t scope, TCppIndex_t idata )
+{
+ if ( scope == GLOBAL_HANDLE )
+ return kTRUE;
+ TClassRef& cr = type_from_handle( scope );
+ if ( cr->Property() & kIsNamespace )
+ return kTRUE;
+ TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At( idata );
+ return m->Property() & kIsPublic;
+}
+
+Bool_t Cppyy::IsStaticData( TCppScope_t scope, TCppIndex_t idata )
+{
+ if ( scope == GLOBAL_HANDLE )
+ return kTRUE;
+ TClassRef& cr = type_from_handle( scope );
+ if ( cr->Property() & kIsNamespace )
+ return kTRUE;
+ TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At( idata );
+ return m->Property() & kIsStatic;
+}
+
+Bool_t Cppyy::IsConstData( TCppScope_t scope, TCppIndex_t idata )
+{
+ if ( scope == GLOBAL_HANDLE ) {
+ TGlobal* gbl = g_globalvars[ idata ];
+ return gbl->Property() & kIsConstant;
+ }
+ TClassRef& cr = type_from_handle( scope );
+ if ( cr.GetClass() ) {
+ TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At( idata );
+ return m->Property() & kIsConstant;
+ }
+ return kFALSE;
+}
+
+Bool_t Cppyy::IsEnumData( TCppScope_t scope, TCppIndex_t idata )
+{
+ if ( scope == GLOBAL_HANDLE ) {
+ TGlobal* gbl = g_globalvars[ idata ];
+ return gbl->Property() & kIsEnum;
+ }
+ TClassRef& cr = type_from_handle( scope );
+ if ( cr.GetClass() ) {
+ TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At( idata );
+ return m->Property() & kIsEnum;
+ }
+ return kFALSE;
+}
+
+Int_t Cppyy::GetDimensionSize( TCppScope_t scope, TCppIndex_t idata, int dimension )
+{
+ if ( scope == GLOBAL_HANDLE ) {
+ TGlobal* gbl = g_globalvars[ idata ];
+ return gbl->GetMaxIndex( dimension );
+ }
+ TClassRef& cr = type_from_handle( scope );
+ if ( cr.GetClass() ) {
+ TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At( idata );
+ return m->GetMaxIndex( dimension );
+ }
+ return (Int_t)-1;
+}
+
+
+static inline
+std::vector<TParameter> vsargs_to_parvec(void* args, int nargs)
+{
+ std::vector<TParameter> v;
+ v.reserve(nargs);
+ for (int i=0; i<nargs; ++i)
+ v.push_back(((TParameter*)args)[i]);
+ return v;
+}
+
+//- C-linkage wrappers -------------------------------------------------------
+extern "C" {
/* name to opaque C++ scope representation -------------------------------- */
-int cppyy_num_scopes(cppyy_scope_t handle) {
- return 0;
+int cppyy_num_scopes(cppyy_scope_t parent) {
+ return (int)Cppyy::GetNumScopes(parent);
+}
+
+char* cppyy_scope_name(cppyy_scope_t parent, int iscope) {
+ return cppstring_to_cstring(Cppyy::GetScopeName(parent, iscope));
}
char* cppyy_resolve_name(const char* cppitem_name) {
- std::cout << " RESOLVING: " << cppitem_name << std::endl;
- return cppstring_to_cstring(cppitem_name);
+ return cppstring_to_cstring(Cppyy::ResolveName(cppitem_name));
}
cppyy_scope_t cppyy_get_scope(const char* scope_name) {
- const cling::LookupHelper& lh = gCppyy_Cling->getLookupHelper();
- const Type* type = 0;
- const Decl* decl = lh.findScope(scope_name, &type, /* intantiateTemplate= */ true);
- if (!decl) {
- //std::string buf = TClassEdit::InsertStd(name);
- //decl = lh.findScope(buf, &type, /* intantiateTemplate= */ true);
- }
- if (!decl && type) {
- const TagType* tagtype = type->getAs<TagType>();
- if (tagtype) {
- decl = tagtype->getDecl();
- }
- }
-
- std::cout << "FOR: " << scope_name << " RECEIVED: " << type << " AND: " << decl << std::endl;
- if (decl) {
- DeclContext* dc = llvm::cast<DeclContext>(const_cast<Decl*>(decl));
- SimpleScope* s = new SimpleScope;
- for (DeclContext::decl_iterator idecl = dc->decls_begin(); *idecl; ++idecl) {
- if (FunctionDecl* m = llvm::dyn_cast_or_null<FunctionDecl>(*idecl))
- s->m_methods.push_back(m);
- else if (FieldDecl* d = llvm::dyn_cast_or_null<FieldDecl>(*idecl))
- s->m_data.push_back(d);
- }
- s_scopes[(cppyy_scope_t)decl] = s;
- }
-
- return (cppyy_scope_t)decl; // lookup failure return 0 (== error)
+ return cppyy_scope_t(Cppyy::GetScope(scope_name));
}
+cppyy_type_t cppyy_get_template(const char* template_name) {
+ return cppyy_type_t(Cppyy::GetTemplate(template_name));
+}
-/* method/function dispatching -------------------------------------------- */
+cppyy_type_t cppyy_actual_class(cppyy_type_t klass, cppyy_object_t obj) {
+ return cppyy_type_t(Cppyy::GetActualClass(klass, (void*)obj));
+}
-// TODO: expect the below to live in libCling.so
-static CPPYY_Cling_Wrapper_t make_wrapper(const FunctionDecl* fdecl);
-static void exec_with_valref_return(void* address, cling::StoredValueRef* ret, const FunctionDecl*);
-static long long sv_to_long_long(const cling::StoredValueRef& svref);
-// -- TODO: expect the above to live in libCling.so
+/* memory management ------------------------------------------------------ */
+cppyy_object_t cppyy_allocate(cppyy_type_t type) {
+ return cppyy_object_t(Cppyy::Allocate(type));
+}
-template<typename T>
-static inline T cppyy_call_T(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
- if (s_wrappers.find(method) == s_wrappers.end()) {
- make_wrapper((FunctionDecl*)method);
- }
- cling::StoredValueRef ret;
- // std::vector<void*> arguments = build_args(nargs, args);
- // CPPYY_Cling_Wrapper_t cb = (CPPYY_Cling_Wrapper_t)method;
- exec_with_valref_return((void*)self, &ret, (FunctionDecl*)method);
- // (*cb)((void*)self, nargs, const_cast<void**>(arguments.data()), ret);
- return static_cast<T>(sv_to_long_long(ret));
+void cppyy_deallocate(cppyy_type_t type, cppyy_object_t self) {
+ Cppyy::Deallocate(type, (void*)self);
}
+void cppyy_destruct(cppyy_type_t type, cppyy_object_t self) {
+ Cppyy::Destruct(type, (void*)self);
+}
+/* method/function dispatching -------------------------------------------- */
+void cppyy_call_v(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ std::vector<TParameter> parvec = vsargs_to_parvec(args, nargs);
+ Cppyy::CallV(method, (void*)self, &parvec);
+}
+
+unsigned char cppyy_call_b(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ std::vector<TParameter> parvec = vsargs_to_parvec(args, nargs);
+ return (unsigned char)Cppyy::CallB(method, (void*)self, &parvec);
+}
+
+char cppyy_call_c(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ std::vector<TParameter> parvec = vsargs_to_parvec(args, nargs);
+ return (char)Cppyy::CallC(method, (void*)self, &parvec);
+}
+
+short cppyy_call_h(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ std::vector<TParameter> parvec = vsargs_to_parvec(args, nargs);
+ return (short)Cppyy::CallH(method, (void*)self, &parvec);
+}
+
int cppyy_call_i(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
- return cppyy_call_T<int>(method, self, nargs, args);
+ std::vector<TParameter> parvec = vsargs_to_parvec(args, nargs);
+ return (int)Cppyy::CallI(method, (void*)self, &parvec);
+}
+
+long cppyy_call_l(cppyy_method_t method, cppyy_object_t self, int nargs, void* args){
+ std::vector<TParameter> parvec = vsargs_to_parvec(args, nargs);
+ return (long)Cppyy::CallL(method, (void*)self, &parvec);
+}
+
+long long cppyy_call_ll(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ std::vector<TParameter> parvec = vsargs_to_parvec(args, nargs);
+ return (long long)Cppyy::CallLL(method, (void*)self, &parvec);
}
+float cppyy_call_f(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ std::vector<TParameter> parvec = vsargs_to_parvec(args, nargs);
+ return (float)Cppyy::CallF(method, (void*)self, &parvec);
+}
+
+double cppyy_call_d(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ std::vector<TParameter> parvec = vsargs_to_parvec(args, nargs);
+ return (double)Cppyy::CallD(method, (void*)self, &parvec);
+}
+
+void* cppyy_call_r(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ std::vector<TParameter> parvec = vsargs_to_parvec(args, nargs);
+ return (void*)Cppyy::CallR(method, (void*)self, &parvec);
+}
+
+char* cppyy_call_s(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ std::vector<TParameter> parvec = vsargs_to_parvec(args, nargs);
+ return cppstring_to_cstring(Cppyy::CallS(method, (void*)self, &parvec));
+}
+
+cppyy_object_t cppyy_constructor(cppyy_method_t method, cppyy_type_t klass, int nargs, void* args) {
+ std::vector<TParameter> parvec = vsargs_to_parvec(args, nargs);
+ return cppyy_object_t(Cppyy::CallConstructor(method, klass, &parvec));
+// return cppyy_object_t(Cppyy::CallConstructor(method, klass, args));
+}
+cppyy_object_t cppyy_call_o(cppyy_method_t method, cppyy_object_t self, int nargs, void* args, cppyy_type_t result_type) {
+ std::vector<TParameter> parvec = vsargs_to_parvec(args, nargs);
+ return cppyy_object_t(Cppyy::CallO(method, (void*)self, &parvec, result_type));
+}
-cppyy_methptrgetter_t cppyy_get_methptr_getter(cppyy_type_t /* handle */, cppyy_index_t /* method_index */) {
- return (cppyy_methptrgetter_t)0;
+cppyy_methptrgetter_t cppyy_get_methptr_getter(cppyy_scope_t scope, cppyy_index_t idx) {
+ return cppyy_methptrgetter_t(Cppyy::GetMethPtrGetter(scope, idx));
}
/* handling of function argument buffer ----------------------------------- */
-void* cppyy_allocate_function_args(size_t nargs) {
- CPPYY_G__value* args = (CPPYY_G__value*)malloc(nargs*sizeof(CPPYY_G__value));
- for (size_t i = 0; i < nargs; ++i)
- args[i].type = 'l';
- return (void*)args;
+void* cppyy_allocate_function_args(int nargs){
+ return (void*)Cppyy::AllocateFunctionArgs(nargs);
}
-void cppyy_deallocate_function_args(void* args) {
- free(args);
+void cppyy_deallocate_function_args(void* args){
+ Cppyy::DeallocateFunctionArgs(args);
}
-size_t cppyy_function_arg_sizeof() {
- return sizeof(CPPYY_G__value);
+size_t cppyy_function_arg_sizeof(){
+ return (size_t)Cppyy::GetFunctionArgSizeof();
}
-size_t cppyy_function_arg_typeoffset() {
- return offsetof(CPPYY_G__value, type);
+size_t cppyy_function_arg_typeoffset(){
+ return (size_t)Cppyy::GetFunctionArgTypeoffset();
}
/* scope reflection information ------------------------------------------- */
-int cppyy_is_namespace(cppyy_scope_t /* handle */) {
- return 0;
-}
+int cppyy_is_namespace(cppyy_scope_t scope) {
+ return (int)Cppyy::IsNamespace(scope);
+}
-int cppyy_is_enum(const char* /* type_name */) {
- return 0;
+int cppyy_is_enum(const char* type_name){
+ return (int)Cppyy::IsEnum(type_name);
}
-
-
+
+
/* class reflection information ------------------------------------------- */
-char* cppyy_final_name(cppyy_type_t handle) {
- for (NamedHandles_t::iterator isp = s_named.begin(); isp != s_named.end(); ++isp) {
- if (isp->second == (cppyy_scope_t)handle)
- return cppstring_to_cstring(isp->first);
- }
- return cppstring_to_cstring("<unknown>");
+char* cppyy_final_name(cppyy_type_t type) {
+ return cppstring_to_cstring(Cppyy::GetFinalName(type));
+}
+
+char* cppyy_scoped_final_name(cppyy_type_t type) {
+ return cppstring_to_cstring(Cppyy::GetScopedFinalName(type));
+}
+
+int cppyy_has_complex_hierarchy(cppyy_type_t type) {
+ return (int)Cppyy::HasComplexHierarchy(type);
+}
+
+int cppyy_num_bases(cppyy_type_t type) {
+ return (int)Cppyy::GetNumBases(type);
+}
+
+char* cppyy_base_name(cppyy_type_t type, int base_index){
+ return cppstring_to_cstring(Cppyy::GetBaseName (type, base_index));
+}
+
+int cppyy_is_subtype(cppyy_type_t derived, cppyy_type_t base){
+ return (int)Cppyy::IsSubtype( derived, base );
}
-char* cppyy_scoped_final_name(cppyy_type_t handle) {
- return cppyy_final_name(handle);
-}
-int cppyy_has_complex_hierarchy(cppyy_type_t /* handle */) {
- return 1;
+/* calculate offsets between declared and actual type, up-cast: direction > 0; down-cast: direction < 0 */
+ptrdiff_t cppyy_base_offset(cppyy_type_t derived, cppyy_type_t base, cppyy_object_t address, int direction) {
+ return (ptrdiff_t)Cppyy::GetBaseOffset(derived, base, (void*)address, direction, 0);
}
/* method/function reflection information --------------------------------- */
-int cppyy_num_methods(cppyy_scope_t handle) {
- SimpleScope* s = scope_from_handle(handle);
- if (!s) return 0;
- return s->m_methods.size();
+int cppyy_num_methods(cppyy_scope_t scope) {
+ return (int)Cppyy::GetNumMethods (scope);
+}
+
+cppyy_index_t cppyy_method_index_at(cppyy_scope_t scope, int imeth) {
+ return cppyy_index_t(Cppyy::GetMethodIndexAt (scope, imeth));
+}
+
+cppyy_index_t* cppyy_method_indices_from_name(cppyy_scope_t scope, const char* name){
+//NEED TO DO:
+ return (cppyy_index_t*)0;
+// return (cppyy_index_t*)Cppyy::GetMethodsFromName(scope, name);
+}
+
+char* cppyy_method_name(cppyy_scope_t scope, cppyy_index_t idx) {
+ TFunction* f = type_get_method(scope, idx);
+ return cppstring_to_cstring(Cppyy::GetMethodName((Cppyy::TCppMethod_t)f));
+}
+
+char* cppyy_method_result_type(cppyy_scope_t scope, cppyy_index_t idx) {
+ TFunction* f = type_get_method(scope, idx);
+ return cppstring_to_cstring(Cppyy::GetMethodResultType((Cppyy::TCppMethod_t)f));
}
-cppyy_index_t cppyy_method_index_at(cppyy_scope_t /* scope */, int imeth) {
- return (cppyy_index_t)imeth;
+int cppyy_method_num_args(cppyy_scope_t scope, cppyy_index_t idx) {
+ TFunction* f = type_get_method(scope, idx);
+ return (int)Cppyy::GetMethodNumArgs((Cppyy::TCppMethod_t)f);
}
-char* cppyy_method_name(cppyy_scope_t handle, cppyy_index_t method_index) {
- SimpleScope* s = scope_from_handle(handle);
- if (!s) return cppstring_to_cstring("<unknown>");
- FunctionDecl* meth = s->m_methods.at(method_index);
- std::cout << " METHOD NAME: " << meth->getDeclName().getAsString() << std::endl;
- return cppstring_to_cstring(meth->getDeclName().getAsString());
+int cppyy_method_req_args(cppyy_scope_t scope, cppyy_index_t idx) {
+ TFunction* f = type_get_method(scope, idx);
+ return (int)Cppyy::GetMethodReqArgs((Cppyy::TCppMethod_t)f);
}
-char* cppyy_method_result_type(cppyy_scope_t handle, cppyy_index_t method_index) {
- SimpleScope* s = scope_from_handle(handle);
- if (!s) return cppstring_to_cstring("<unknown>");
- FunctionDecl* meth = s->m_methods.at(method_index);
- const std::string& ret_type =
- qualtype_to_string(meth->getCallResultType(), meth->getASTContext());
- std::cout << " -> RET TYPE: " << ret_type << std::endl;
- return cppstring_to_cstring(ret_type);
+char* cppyy_method_arg_type(cppyy_scope_t scope, cppyy_index_t idx, int arg_index) {
+ TFunction* f = type_get_method(scope, idx);
+ return cppstring_to_cstring(Cppyy::GetMethodArgType((Cppyy::TCppMethod_t)f, arg_index));
}
-
-int cppyy_method_num_args(cppyy_scope_t /* handle */, cppyy_index_t /* method_index */) {
- return 1;
+
+char* cppyy_method_arg_default(cppyy_scope_t scope, cppyy_index_t idx, int arg_index) {
+ TFunction* f = type_get_method(scope, idx);
+ return cppstring_to_cstring(Cppyy::GetMethodArgDefault((Cppyy::TCppMethod_t)f, arg_index));
}
-int cppyy_method_req_args(cppyy_scope_t handle, cppyy_index_t method_index) {
- return cppyy_method_num_args(handle, method_index);
+char* cppyy_method_signature(cppyy_scope_t scope, cppyy_index_t idx) {
+ return cppstring_to_cstring(Cppyy::GetMethodSignature(scope, idx));
}
-char* cppyy_method_arg_type(cppyy_scope_t /* handle */, cppyy_index_t /* method_index */, int /* arg_index */) {
- return cppstring_to_cstring("double");
+int cppyy_method_is_template(cppyy_scope_t scope, cppyy_index_t idx) {
+ TFunction* f = type_get_method(scope, idx);
+ return (int)Cppyy::IsMethodTemplate((Cppyy::TCppMethod_t)f);
}
-char* cppyy_method_arg_default(cppyy_scope_t handle, cppyy_index_t method_index, int arg_index) {
- return cppstring_to_cstring("");
+int cppyy_method_num_template_args(cppyy_scope_t scope, cppyy_index_t idx) {
+ return (int)Cppyy::GetMethodNumTemplateArgs(scope, idx);
}
-char* cppyy_method_signature(cppyy_scope_t /* handle */, cppyy_index_t /* method_index */) {
- return cppstring_to_cstring("double");
+char* cppyy_method_template_arg_name(cppyy_scope_t scope, cppyy_index_t idx, cppyy_index_t iarg) {
+ return cppstring_to_cstring(Cppyy::GetMethodTemplateArgName(scope, idx, iarg));
}
-int cppyy_method_is_template(cppyy_scope_t /* handle */, cppyy_index_t /* method_index */) {
- return 0;
+cppyy_method_t cppyy_get_method(cppyy_scope_t scope, cppyy_index_t idx) {
+ return cppyy_method_t(Cppyy::GetMethod(scope, idx));
}
-
-cppyy_method_t cppyy_get_method(cppyy_scope_t handle, cppyy_index_t method_index) {
- SimpleScope* s = scope_from_handle(handle);
- if (!s) return (cppyy_method_t)0;
- return (cppyy_method_t)s->m_methods.at(method_index);
+
+cppyy_index_t cppyy_get_global_operator(cppyy_scope_t scope, cppyy_scope_t lc, cppyy_scope_t rc, const char* op) {
+ return cppyy_index_t(Cppyy::GetGlobalOperator(scope, lc, rc, op));
}
-/* method properties ----------------------------------------------------- */
-int cppyy_is_constructor(cppyy_type_t /* handle */, cppyy_index_t /* method_index */) {
- return 0;
+/* method properties ------------------------------------------------------ */
+int cppyy_is_constructor(cppyy_type_t type, cppyy_index_t idx) {
+ TFunction* f = type_get_method(type, idx);
+ return (int)Cppyy::IsConstructor((Cppyy::TCppMethod_t)f);
}
-int cppyy_is_staticmethod(cppyy_type_t /* handle */, cppyy_index_t /* method_index */) {
- return 1;
+int cppyy_is_staticmethod(cppyy_type_t type, cppyy_index_t idx) {
+ TFunction* f = type_get_method(type, idx);
+ return (int)Cppyy::IsStaticMethod((Cppyy::TCppMethod_t)f);
}
/* data member reflection information ------------------------------------- */
-int cppyy_num_datamembers(cppyy_scope_t /* handle */) {
- return 0;
+int cppyy_num_datamembers(cppyy_scope_t scope) {
+ return (int)Cppyy::GetNumDatamembers(scope);
}
+char* cppyy_datamember_name(cppyy_scope_t scope, int datamember_index) {
+ return cppstring_to_cstring(Cppyy::GetDatamemberName(scope, datamember_index));
+}
-/* misc helpers ----------------------------------------------------------- */
-void cppyy_free(void* ptr) {
- free(ptr);
+char* cppyy_datamember_type(cppyy_scope_t scope, int datamember_index) {
+ return cppstring_to_cstring(Cppyy::GetDatamemberType(scope, datamember_index));
}
+ptrdiff_t cppyy_datamember_offset(cppyy_scope_t scope, int datamember_index) {
+ return ptrdiff_t(Cppyy::GetDatamemberOffset(scope, datamember_index));
+}
-void* cppyy_load_dictionary(const char* lib_name) {
- // TODO: need to rethink this; for now it creates reflection info from
- // <lib_name>.h while loading lib<lib_name>.so
-
- // Load a library file in cling's memory.
- // if 'system' is true, the library is never unloaded.
- // Return 0 on success, -1 on failure.
- // R__LOCKGUARD2(gInterpreterMutex);
- std::cout << " NOW LOADING: " << lib_name << std::endl;
-
- cling::StoredValueRef call_res;
- cling::Interpreter::CompilationResult comp_res = cling::Interpreter::kSuccess;
- std::ostringstream line;
- line << "#include \"" << lib_name << ".h\"";
- gCppyy_MetaProcessor->process(line.str().c_str(), comp_res, &call_res);
-
- std::string to_load = "lib";
- to_load += lib_name;
- to_load += ".so";
- cling::DynamicLibraryManager::LoadLibResult res
- = gCppyy_Cling->getDynamicLibraryManager()->loadLibrary(to_load, /* not unload */ true);
- // if (res == cling::DynamicLibraryManager::kLoadLibSuccess) {
- // UpdateListOfLoadedSharedLibraries();
- // }
- switch (res) {
- case cling::DynamicLibraryManager::kLoadLibSuccess: return (void*)1;
- case cling::DynamicLibraryManager::kLoadLibExists: return (void*)2;
- default: break;
- };
- return (void*)1;
-}
-
-
-/* to-be libCling code taken from ROOT/meta ------------------------------- */
-
-// TODO: expect the below to live in libCling.so
-
-template <typename T>
-T sv_to_long_long_u_or_not(const cling::StoredValueRef& svref) {
- const cling::Value& valref = svref.get();
- QualType QT = valref.getClangType();
- if (QT.isNull()) {
- print_error("sv_to_long_long_u_or_not", "null type!");
- return 0;
- }
- llvm::GenericValue gv = valref.getGV();
- if (QT->isMemberPointerType()) {
- const MemberPointerType* MPT =
- QT->getAs<MemberPointerType>();
- if (MPT->isMemberDataPointer()) {
- return (T) (ptrdiff_t) gv.PointerVal;
- }
- return (T) gv.PointerVal;
- }
- if (QT->isPointerType() || QT->isArrayType() || QT->isRecordType() ||
- QT->isReferenceType()) {
- return (T) gv.PointerVal;
- }
- if (const EnumType* ET = llvm::dyn_cast<EnumType>(&*QT)) {
- if (ET->getDecl()->getIntegerType()->hasSignedIntegerRepresentation())
- return (T) gv.IntVal.getSExtValue();
- else
- return (T) gv.IntVal.getZExtValue();
- }
- if (const BuiltinType* BT = llvm::dyn_cast<BuiltinType>(&*QT)) {
- if (BT->isSignedInteger()) {
- return gv.IntVal.getSExtValue();
- } else if (BT->isUnsignedInteger()) {
- return (T) gv.IntVal.getZExtValue();
- } else {
- switch (BT->getKind()) {
- case BuiltinType::Float:
- return (T) gv.FloatVal;
- case BuiltinType::Double:
- return (T) gv.DoubleVal;
- case BuiltinType::LongDouble:
- // FIXME: Implement this!
- break;
- case BuiltinType::NullPtr:
- // C++11 nullptr
- return 0;
- default: break;
- }
- }
- }
- print_error("sv_to_long_long_u_or_not", "cannot handle this type!");
- QT->dump();
- return 0;
+int cppyy_datamember_index(cppyy_scope_t scope, const char* name) {
+ return (int)Cppyy::GetDatamemberIndex(scope, name);
}
-static long long sv_to_long_long(const cling::StoredValueRef& svref) {
- return sv_to_long_long_u_or_not<long long>(svref);
+
+
+/* data member properties ------------------------------------------------- */
+int cppyy_is_publicdata(cppyy_type_t type, int datamember_index) {
+ return (int)Cppyy::IsPublicData(type, datamember_index);
}
-static
-unsigned long long sv_to_ulong_long(const cling::StoredValueRef& svref) {
- return sv_to_long_long_u_or_not<unsigned long long>(svref);
+int cppyy_is_staticdata(cppyy_type_t type, int datamember_index) {
+ return (int)Cppyy::IsStaticData(type, datamember_index);
}
-namespace {
+/* misc helpers ----------------------------------------------------------- */
+RPY_EXTERN
+void* cppyy_load_dictionary(const char* lib_name) {
+ return (void*)(gInterpreter->Load(lib_name) == 0);
+}
-class ValHolder {
-public:
- union {
- long double ldbl;
- double dbl;
- float flt;
- //__uint128_t ui128;
- //__int128_t i128;
- unsigned long long ull;
- long long ll;
- unsigned long ul;
- long l;
- unsigned int ui;
- int i;
- unsigned short us;
- short s;
- //char32_t c32;
- //char16_t c16;
- //unsigned wchar_t uwc; - non-standard
- wchar_t wc;
- unsigned char uc;
- signed char sc;
- char c;
- bool b;
- void* vp;
- } u;
-};
+long long cppyy_strtoll(const char* str) {
+ return strtoll(str, NULL, 0);
+}
-} // unnamed namespace
+unsigned long long cppyy_strtoull(const char* str) {
+ return strtoull(str, NULL, 0);
+}
-static void exec(void* address, void* ret, const FunctionDecl* fdecl) {
- std::vector<ValHolder> vh_ary;
- std::vector<void*> vp_ary;
-
- //
- // Convert the arguments from cling::StoredValueRef to their
- // actual type and store them in a holder for passing to the
- // wrapper function by pointer to value.
- //
- unsigned num_params = fdecl->getNumParams();
- /* unsigned num_args = fArgVals.size();
-
- if (num_args < fdecl->getMinRequiredArguments ()) {
- Error("TClingCallFunc::exec",
- "Not enough arguments provided for %s (%d instead of the minimum %d)",
- fMethod->Name(ROOT::TMetaUtils::TNormalizedCtxt(fInterp->getLookupHelper())),
- num_args,fdecl->getMinRequiredArguments ());
- return;
- }
- if (address == 0 && llvm::dyn_cast<CXXMethodDecl>(fdecl)
- && !(llvm::dyn_cast<CXXMethodDecl>(fdecl))->isStatic()
- && !llvm::dyn_cast<CXXConstructorDecl>(fdecl)) {
- Error("TClingCallFunc::exec",
- "The method %s is called without an object.",
- fMethod->Name(ROOT::TMetaUtils::TNormalizedCtxt(fInterp->getLookupHelper())));
- return;
- }
- vh_ary.reserve(num_args);
- vp_ary.reserve(num_args);
- for (unsigned i = 0U; i < num_args; ++i) {
- QualType Ty;
- if (i < num_params) {
- const ParmVarDecl* PVD = fdecl->getParamDecl(i);
- Ty = PVD->getType();
- }
- else {
- Ty = fArgVals[i].get().getClangType();
- }
- QualType QT = Ty.getCanonicalType();
- if (QT->isReferenceType()) {
- ValHolder vh;
- vh.u.vp = (void*) sv_to_ulong_long(fArgVals[i]);
- vh_ary.push_back(vh);
- vp_ary.push_back(&vh_ary.back());
- }
- else if (QT->isMemberPointerType()) {
- ValHolder vh;
- vh.u.vp = (void*) sv_to_ulong_long(fArgVals[i]);
- vh_ary.push_back(vh);
- vp_ary.push_back(&vh_ary.back());
- }
- else if (QT->isPointerType() || QT->isArrayType()) {
- ValHolder vh;
- vh.u.vp = (void*) sv_to_ulong_long(fArgVals[i]);
- vh_ary.push_back(vh);
- vp_ary.push_back(&vh_ary.back());
- }
- else if (QT->isRecordType()) {
- ValHolder vh;
- vh.u.vp = (void*) sv_to_ulong_long(fArgVals[i]);
- vh_ary.push_back(vh);
- vp_ary.push_back(&vh_ary.back());
- }
- else if (const EnumType* ET = llvm::dyn_cast<EnumType>(&*QT)) {
- // Note: We may need to worry about the underlying type
- // of the enum here.
- (void) ET;
- ValHolder vh;
- vh.u.i = (int) sv_to_long_long(fArgVals[i]);
- vh_ary.push_back(vh);
- vp_ary.push_back(&vh_ary.back());
- }
- else if (const BuiltinType* BT = llvm::dyn_cast<BuiltinType>(&*QT)) {
- //
- // WARNING!!!
- //
- // This switch is organized in order-of-declaration
- // so that the produced assembly code is optimal.
- // Do not reorder!
- //
- switch (BT->getKind()) {
- //
- // Builtin Types
- //
- case BuiltinType::Void: {
- // void
- print_error("exec", "invalid argument type (void)");
- return;
- }
- //
- // Unsigned Types
- //
- case BuiltinType::Bool: {
- // bool
- ValHolder vh;
- vh.u.b = (bool) sv_to_ulong_long(fArgVals[i]);
- vh_ary.push_back(vh);
- vp_ary.push_back(&vh_ary.back());
- break;
- }
- case BuiltinType::Char_U: {
- // char on targets where it is unsigned
- ValHolder vh;
- vh.u.c = (char) sv_to_ulong_long(fArgVals[i]);
- vh_ary.push_back(vh);
- vp_ary.push_back(&vh_ary.back());
- break;
- }
- case BuiltinType::UChar: {
- // unsigned char
- ValHolder vh;
- vh.u.uc = (unsigned char) sv_to_ulong_long(fArgVals[i]);
- vh_ary.push_back(vh);
- vp_ary.push_back(&vh_ary.back());
- break;
- }
- case BuiltinType::WChar_U: {
- // wchar_t on targets where it is unsigned.
- // The standard doesn't allow to specify signednedd of wchar_t
- // thus this maps simply to wchar_t.
- ValHolder vh;
- vh.u.wc = (wchar_t) sv_to_ulong_long(fArgVals[i]);
- vh_ary.push_back(vh);
- vp_ary.push_back(&vh_ary.back());
- break;
- }
- case BuiltinType::Char16:
- case BuiltinType::Char32: {
- print_error("exec", "unsupported argument");
- QT->dump();
- return;
- }
- case BuiltinType::UShort: {
- // unsigned short
- ValHolder vh;
- vh.u.us = (unsigned short) sv_to_ulong_long(fArgVals[i]);
- vh_ary.push_back(vh);
- vp_ary.push_back(&vh_ary.back());
- break;
- }
- case BuiltinType::UInt: {
- // unsigned int
- ValHolder vh;
- vh.u.ui = (unsigned int) sv_to_ulong_long(fArgVals[i]);
- vh_ary.push_back(vh);
- vp_ary.push_back(&vh_ary.back());
- break;
- }
- case BuiltinType::ULong: {
- // unsigned long
- ValHolder vh;
- vh.u.ul = (unsigned long) sv_to_ulong_long(fArgVals[i]);
- vh_ary.push_back(vh);
- vp_ary.push_back(&vh_ary.back());
- break;
- }
- case BuiltinType::ULongLong: {
- // unsigned long long
- ValHolder vh;
- vh.u.ull = (unsigned long long) sv_to_ulong_long(fArgVals[i]);
- vh_ary.push_back(vh);
- vp_ary.push_back(&vh_ary.back());
- break;
- }
- case BuiltinType::UInt128: {
- print_error("exec", "unsupported argument");
- QT->dump();
- return;
- }
- //
- // Signed Types
- //
- case BuiltinType::Char_S: {
- // char on targets where it is signed
- ValHolder vh;
- vh.u.c = (char) sv_to_long_long(fArgVals[i]);
- vh_ary.push_back(vh);
- vp_ary.push_back(&vh_ary.back());
- break;
- }
- case BuiltinType::SChar: {
- // signed char
- ValHolder vh;
- vh.u.sc = (signed char) sv_to_long_long(fArgVals[i]);
- vh_ary.push_back(vh);
- vp_ary.push_back(&vh_ary.back());
- break;
- }
- case BuiltinType::WChar_S: {
- // wchar_t on targets where it is signed.
- // The standard doesn't allow to specify signednedd of wchar_t
- // thus this maps simply to wchar_t.
- ValHolder vh;
- vh.u.wc = (wchar_t) sv_to_long_long(fArgVals[i]);
- vh_ary.push_back(vh);
- vp_ary.push_back(&vh_ary.back());
- break;
- }
- case BuiltinType::Short: {
- // short
- ValHolder vh;
- vh.u.s = (short) sv_to_long_long(fArgVals[i]);
- vh_ary.push_back(vh);
- vp_ary.push_back(&vh_ary.back());
- break;
- }
- case BuiltinType::Int: {
- // int
- ValHolder vh;
- vh.u.i = (int) sv_to_long_long(fArgVals[i]);
- vh_ary.push_back(vh);
- vp_ary.push_back(&vh_ary.back());
- break;
- }
- case BuiltinType::Long: {
- // long
- ValHolder vh;
- vh.u.l = (long) sv_to_long_long(fArgVals[i]);
- vh_ary.push_back(vh);
- vp_ary.push_back(&vh_ary.back());
- break;
- }
- case BuiltinType::LongLong: {
- // long long
- ValHolder vh;
- vh.u.ll = (long long) sv_to_long_long(fArgVals[i]);
- vh_ary.push_back(vh);
- vp_ary.push_back(&vh_ary.back());
- break;
- }
- case BuiltinType::Int128:
- case BuiltinType::Half: {
- // half in OpenCL, __fp16 in ARM NEON
- print_error("exec", "unsupported argument");
- QT->dump();
- return;
- }
- case BuiltinType::Float: {
- // float
- ValHolder vh;
- vh.u.flt = sv_to<float>(fArgVals[i]);
- vh_ary.push_back(vh);
- vp_ary.push_back(&vh_ary.back());
- break;
- }
- case BuiltinType::Double: {
- // double
- ValHolder vh;
- vh.u.dbl = sv_to<double>(fArgVals[i]);
- vh_ary.push_back(vh);
- vp_ary.push_back(&vh_ary.back());
- break;
- }
- case BuiltinType::LongDouble: {
- // long double
- print_error("exec", "unsupported argument");
- QT->dump();
- return;
- }
- //
- // Language-Specific Types
- //
- case BuiltinType::NullPtr: {
- // C++11 nullptr
- ValHolder vh;
- vh.u.vp = (void*) fArgVals[i].get().getGV().PointerVal;
- vh_ary.push_back(vh);
- vp_ary.push_back(&vh_ary.back());
- break;
- }
- default: {
- print_error("exec", "unsupported argument");
- QT->dump();
- return;
- }
- }
- }
- else {
- print_error("exec", "invalid type (unrecognized)!");
- QT->dump();
- return;
- }
- }*/
-
- CPPYY_Cling_Wrapper_t wrapper = s_wrappers[(cppyy_method_t)fdecl];
- (*wrapper)(address, (int)0/*num_args*/, (void**)vp_ary.data(), ret);
-}
-
-
-static void exec_with_valref_return(void* address, cling::StoredValueRef* ret, const FunctionDecl* fdecl) {
- if (!ret) {
- exec(address, 0, fdecl);
- return;
- }
- std::cout << " USING DECL: " << fdecl << std::endl;
- fdecl->dump();
- ASTContext& Context = fdecl->getASTContext();
-
- if (const CXXConstructorDecl* CD = llvm::dyn_cast<CXXConstructorDecl>(fdecl)) {
- const TypeDecl* TD = llvm::dyn_cast<TypeDecl>(CD->getDeclContext());
- QualType ClassTy(TD->getTypeForDecl(), 0);
- QualType QT = Context.getLValueReferenceType(ClassTy);
- llvm::GenericValue gv;
- exec(address, &gv.PointerVal, fdecl);
- *ret = cling::StoredValueRef::bitwiseCopy(
- *gCppyy_Cling, cling::Value(gv, QT));
- return;
- }
- QualType QT = fdecl->getResultType().getCanonicalType();
- if (QT->isReferenceType()) {
- llvm::GenericValue gv;
- exec(address, &gv.PointerVal, fdecl);
- *ret = cling::StoredValueRef::bitwiseCopy(
- *gCppyy_Cling, cling::Value(gv, QT));
- return;
- }
- else if (QT->isMemberPointerType()) {
- const MemberPointerType* MPT =
- QT->getAs<MemberPointerType>();
- if (MPT->isMemberDataPointer()) {
- // A member data pointer is a actually a struct with one
- // member of ptrdiff_t, the offset from the base of the object
- // storage to the storage for the designated data member.
- llvm::GenericValue gv;
- exec(address, &gv.PointerVal, fdecl);
- *ret = cling::StoredValueRef::bitwiseCopy(
- *gCppyy_Cling, cling::Value(gv, QT));
- return;
- }
- // We are a function member pointer.
- llvm::GenericValue gv;
- exec(address, &gv.PointerVal, fdecl);
- *ret = cling::StoredValueRef::bitwiseCopy(
- *gCppyy_Cling, cling::Value(gv, QT));
- return;
- }
- else if (QT->isPointerType() || QT->isArrayType()) {
- // Note: ArrayType is an illegal function return value type.
- llvm::GenericValue gv;
- exec(address, &gv.PointerVal, fdecl);
- *ret = cling::StoredValueRef::bitwiseCopy(
- *gCppyy_Cling, cling::Value(gv, QT));
- return;
- }
- else if (QT->isRecordType()) {
- uint64_t size = Context.getTypeSizeInChars(QT).getQuantity();
- void* p = ::operator new(size);
- exec(address, p, fdecl);
- *ret = cling::StoredValueRef::bitwiseCopy(
- *gCppyy_Cling, cling::Value(llvm::PTOGV(p), QT));
- return;
- }
- else if (const EnumType* ET = llvm::dyn_cast<EnumType>(&*QT)) {
- // Note: We may need to worry about the underlying type
- // of the enum here.
- (void) ET;
- uint64_t numBits = Context.getTypeSize(QT);
- int retVal = 0;
- exec(address, &retVal, fdecl);
- llvm::GenericValue gv;
- gv.IntVal = llvm::APInt(numBits, (uint64_t)retVal, true /*isSigned*/);
- *ret = cling::StoredValueRef::bitwiseCopy(
- *gCppyy_Cling, cling::Value(gv, QT));
- return;
- }
- else if (const BuiltinType* BT = llvm::dyn_cast<BuiltinType>(&*QT)) {
- llvm::GenericValue gv;
-
- uint64_t numBits = Context.getTypeSize(QT);
- switch (BT->getKind()) {
- //
- // builtin types
- //
- case BuiltinType::Void: {
- exec(address, 0, fdecl);
- return;
- }
- //
- // unsigned integral types
- //
- case BuiltinType::Bool: {
- bool retVal = false;
- exec(address, &retVal, fdecl);
- gv.IntVal = llvm::APInt(numBits, (uint64_t)retVal, false /*isSigned*/);
- break;
- }
- case BuiltinType::Char_U: {
- // char on targets where it is unsigned
- char retVal = '\0';
- exec(address, &retVal, fdecl);
- gv.IntVal = llvm::APInt(numBits, (uint64_t) retVal, false /*isSigned*/);
- break;
- }
- case BuiltinType::UChar: {
- unsigned char retVal = '\0';
- exec(address, &retVal, fdecl);
- gv.IntVal = llvm::APInt(numBits, (uint64_t) retVal, false /*isSigned*/);
- break;
- }
- case BuiltinType::WChar_U: {
- // wchar_t on targets where it is unsigned.
- // The standard doesn't allow to specify signedness of wchar_t
- // thus this maps simply to wchar_t.
- wchar_t retVal = L'\0';
- exec(address, &retVal, fdecl);
- gv.IntVal = llvm::APInt(numBits, (uint64_t) retVal, false /*isSigned*/);
- break;
- }
- case BuiltinType::UShort: {
- unsigned short retVal = 0;
- exec(address, &retVal, fdecl);
- gv.IntVal = llvm::APInt(numBits, (uint64_t) retVal, false /*isSigned*/);
- break;
- }
- case BuiltinType::UInt: {
- unsigned int retVal = 0;
- exec(address, &retVal, fdecl);
- gv.IntVal = llvm::APInt(numBits, (uint64_t) retVal, false /*isSigned*/);
- break;
- }
- case BuiltinType::ULong: {
- // unsigned long
- unsigned long retVal = 0;
- exec(address, &retVal, fdecl);
- gv.IntVal = llvm::APInt(numBits, (uint64_t) retVal, false /*isSigned*/);
- break;
- }
- case BuiltinType::ULongLong: {
- // unsigned long long
- unsigned long long retVal = 0;
- exec(address, &retVal, fdecl);
- gv.IntVal = llvm::APInt(numBits, (uint64_t) retVal, false /*isSigned*/);
- break;
- }
- //
- // signed integral types
- //
- case BuiltinType::Char_S: {
- // char on targets where it is signed
- char retVal = '\0';
- exec(address, &retVal, fdecl);
- gv.IntVal = llvm::APInt(numBits, (uint64_t) retVal, true /*isSigned*/);
- break;
- }
- case BuiltinType::SChar: {
- // signed char
- signed char retVal = '\0';
- exec(address, &retVal, fdecl);
- gv.IntVal = llvm::APInt(numBits, (uint64_t) retVal, true /*isSigned*/);
- break;
- }
- case BuiltinType::WChar_S: {
- // wchar_t on targets where it is signed.
- // The standard doesn't allow to specify signednedd of wchar_t
- // thus this maps simply to wchar_t.
- wchar_t retVal = L'\0';
- exec(address, &retVal, fdecl);
- gv.IntVal = llvm::APInt(numBits, (uint64_t) retVal, true /*isSigned*/);
- break;
- }
- case BuiltinType::Short: {
- // short
- short retVal = 0;
- exec(address, &retVal, fdecl);
- gv.IntVal = llvm::APInt(numBits, (uint64_t) retVal, true /*isSigned*/);
- break;
- }
- case BuiltinType::Int: {
- // int
- int retVal = 0;
- exec(address, &retVal, fdecl);
- gv.IntVal = llvm::APInt(numBits, (uint64_t) retVal, true /*isSigned*/);
- break;
- }
- case BuiltinType::Long: {
- long retVal = 0;
- exec(address, &retVal, fdecl);
- gv.IntVal = llvm::APInt(numBits, (uint64_t) retVal, true /*isSigned*/);
- break;
- }
- case BuiltinType::LongLong: {
- long long retVal = 0;
- exec(address, &retVal, fdecl);
- gv.IntVal = llvm::APInt(numBits, (uint64_t) retVal, true /*isSigned*/);
- break;
- }
- case BuiltinType::Float: {
- exec(address, &gv.FloatVal, fdecl);
- break;
- }
- case BuiltinType::Double: {
- exec(address, &gv.DoubleVal, fdecl);
- break;
- }
- case BuiltinType::Char16:
- case BuiltinType::Char32:
- case BuiltinType::Half:
- case BuiltinType::Int128:
- case BuiltinType::UInt128:
- case BuiltinType::LongDouble:
- case BuiltinType::NullPtr:
- default: {
- print_error("exec_with_valref", "unsupported return type");
- return;
- }
- }
-
- *ret = cling::StoredValueRef::bitwiseCopy(*gCppyy_Cling, cling::Value(gv, QT));
- return;
- }
-
- std::cout << "exec_with_valref: some error occurred ... " << std::endl;
-}
-
-
-static const std::string indent_string(" ");
-static unsigned long long wrapper_serial = 0LL;
-
-void collect_type_info(QualType& QT, std::ostringstream& typedefbuf,
- std::ostringstream& callbuf, std::string& type_name, bool& isReference,
- int& ptrCnt, int indent_level, bool forArgument, const FunctionDecl* fdecl) {
- //
- // Collect information about type type of a function parameter
- // needed for building the wrapper function.
- //
- PrintingPolicy Policy(fdecl->getASTContext().getPrintingPolicy());
- isReference = false;
- ptrCnt = 0;
- if (QT->isRecordType() && forArgument) {
- // Note: We treat object of class type as if it were a reference
- // type because we hold it by pointer.
- isReference = true;
- QT.getAsStringInternal(type_name, Policy);
- // And drop the default arguments if any (at least until the clang
- // type printer properly handle template paratemeter that are enumerator).
- //R__DropDefaultArg(type_name);
- return;
- }
- while (1) {
- if (QT->isArrayType()) {
- ++ptrCnt;
- QT = cast<clang::ArrayType>(QT)->getElementType();
- continue;
- }
- else if (QT->isFunctionPointerType()) {
- std::string fp_typedef_name;
- {
- std::ostringstream nm;
- nm << "FP" << wrapper_serial++;
- type_name = nm.str();
- llvm::raw_string_ostream OS(fp_typedef_name);
- QT.print(OS, Policy, type_name);
- OS.flush();
- }
- for (int i = 0; i < indent_level; ++i) {
- typedefbuf << indent_string;
- }
- typedefbuf << "typedef " << fp_typedef_name << ";\n";
- break;
- }
- else if (QT->isMemberPointerType()) {
- std::string mp_typedef_name;
- {
- std::ostringstream nm;
- nm << "MP" << wrapper_serial++;
- type_name = nm.str();
- llvm::raw_string_ostream OS(mp_typedef_name);
- QT.print(OS, Policy, type_name);
- OS.flush();
- }
- for (int i = 0; i < indent_level; ++i) {
- typedefbuf << indent_string;
- }
- typedefbuf << "typedef " << mp_typedef_name << ";\n";
- break;
- }
- else if (QT->isPointerType()) {
- ++ptrCnt;
- QT = cast<clang::PointerType>(QT)->getPointeeType();
- continue;
- }
- else if (QT->isReferenceType()) {
- isReference = true;
- QT = cast<ReferenceType>(QT)->getPointeeType();
- continue;
- }
- QT.getAsStringInternal(type_name, Policy);
- break;
- }
- // And drop the default arguments if any (at least until the clang
- // type printer properly handle template paratemeter that are enumerator).
- // R__DropDefaultArg(type_name);
-}
-
-void make_narg_ctor(const unsigned N, std::ostringstream& typedefbuf,
- std::ostringstream& callbuf, const std::string& class_name,
- int indent_level, const FunctionDecl* fdecl) {
- // Make a code string that follows this pattern:
- //
- // new ClassName(args...)
- //
- callbuf << "new " << class_name << "(";
- for (unsigned i = 0U; i < N; ++i) {
- const ParmVarDecl* PVD = fdecl->getParamDecl(i);
- QualType Ty = PVD->getType();
- QualType QT = Ty.getCanonicalType();
- std::string type_name;
- bool isReference = false;
- int ptrCnt = 0;
- collect_type_info(QT, typedefbuf, callbuf, type_name,
- isReference, ptrCnt, indent_level, true, fdecl);
- if (i) {
- callbuf << ',';
- if (i % 2) {
- callbuf << ' ';
- }
- else {
- callbuf << "\n";
- for (int j = 0; j <= indent_level; ++j) {
- callbuf << indent_string;
- }
- }
- }
- if (isReference) {
- std::string stars;
- for (int j = 0; j < ptrCnt; ++j) {
- stars.push_back('*');
- }
- callbuf << "**(" << type_name.c_str() << stars << "**)args["
- << i << "]";
- }
- else if (ptrCnt) {
- std::string stars;
- for (int j = 0; j < ptrCnt; ++j) {
- stars.push_back('*');
- }
- callbuf << "*(" << type_name.c_str() << stars << "*)args["
- << i << "]";
- }
- else {
- callbuf << "*(" << type_name.c_str() << "*)args[" << i << "]";
- }
- }
- callbuf << ")";
-}
-
-void make_narg_call(const unsigned N, std::ostringstream& typedefbuf,
- std::ostringstream& callbuf, const std::string& class_name,int indent_level, const FunctionDecl* fdecl) {
- //
- // Make a code string that follows this pattern:
- //
- // ((<class>*)obj)-><method>(*(<arg-i-type>*)args[i], ...)
- //
- if (const CXXMethodDecl* MD = llvm::dyn_cast<CXXMethodDecl>(fdecl)) {
- // This is a class, struct, or union member.
- if (MD->isConst())
- callbuf << "((const " << class_name << "*)obj)->";
- else
- callbuf << "((" << class_name << "*)obj)->";
- }
- else if (const NamedDecl* ND = llvm::dyn_cast<NamedDecl>(fdecl->getDeclContext())) {
- // This is a namespace member.
- (void) ND;
- callbuf << class_name << "::";
- }
- // callbuf << fMethod->Name() << "(";
- {
- std::string name;
- {
- llvm::raw_string_ostream stream(name);
- fdecl->getNameForDiagnostic(stream, fdecl->getASTContext().getPrintingPolicy(), /*Qualified=*/false);
- }
- callbuf << name << "(";
- }
- for (unsigned i = 0U; i < N; ++i) {
- const ParmVarDecl* PVD = fdecl->getParamDecl(i);
- QualType Ty = PVD->getType();
- QualType QT = Ty.getCanonicalType();
- std::string type_name;
- bool isReference = false;
- int ptrCnt = 0;
- collect_type_info(QT, typedefbuf, callbuf, type_name,
- isReference, ptrCnt, indent_level, true, fdecl);
- if (i) {
- callbuf << ',';
- if (i % 2) {
- callbuf << ' ';
- }
- else {
- callbuf << "\n";
- for (int j = 0; j <= indent_level; ++j) {
- callbuf << indent_string;
- }
- }
- }
- if (isReference) {
- std::string stars;
- for (int j = 0; j < ptrCnt; ++j) {
- stars.push_back('*');
- }
- callbuf << "**(" << type_name.c_str() << stars << "**)args["
- << i << "]";
- }
- else if (ptrCnt) {
- std::string stars;
- for (int j = 0; j < ptrCnt; ++j) {
- stars.push_back('*');
- }
- callbuf << "*(" << type_name.c_str() << stars << "*)args["
- << i << "]";
- }
- else {
- callbuf << "*(" << type_name.c_str() << "*)args[" << i << "]";
- }
- }
- callbuf << ")";
-}
-
-void make_narg_ctor_with_return(const unsigned N, const std::string& class_name,
- std::ostringstream& buf, int indent_level, const FunctionDecl* fdecl) {
- // Make a code string that follows this pattern:
- //
- // if (ret) {
- // (*(ClassName**)ret) = new ClassName(args...);
- // }
- // else {
- // new ClassName(args...);
- // }
- //
- for (int i = 0; i < indent_level; ++i) {
- buf << indent_string;
- }
- buf << "if (ret) {\n";
- ++indent_level;
- {
- std::ostringstream typedefbuf;
- std::ostringstream callbuf;
- //
- // Write the return value assignment part.
- //
- for (int i = 0; i < indent_level; ++i) {
- callbuf << indent_string;
- }
- callbuf << "(*(" << class_name << "**)ret) = ";
- //
- // Write the actual new expression.
- //
- make_narg_ctor(N, typedefbuf, callbuf, class_name, indent_level, fdecl);
- //
- // End the new expression statement.
- //
- callbuf << ";\n";
- for (int i = 0; i < indent_level; ++i) {
- callbuf << indent_string;
- }
- callbuf << "return;\n";
- //
- // Output the whole new expression and return statement.
- //
- buf << typedefbuf.str() << callbuf.str();
- }
- --indent_level;
- for (int i = 0; i < indent_level; ++i) {
- buf << indent_string;
- }
- buf << "}\n";
- for (int i = 0; i < indent_level; ++i) {
- buf << indent_string;
- }
- buf << "else {\n";
- ++indent_level;
- {
- std::ostringstream typedefbuf;
- std::ostringstream callbuf;
- for (int i = 0; i < indent_level; ++i) {
- callbuf << indent_string;
- }
- make_narg_ctor(N, typedefbuf, callbuf, class_name, indent_level, fdecl);
- callbuf << ";\n";
- for (int i = 0; i < indent_level; ++i) {
- callbuf << indent_string;
- }
- callbuf << "return;\n";
- buf << typedefbuf.str() << callbuf.str();
- }
- --indent_level;
- for (int i = 0; i < indent_level; ++i) {
- buf << indent_string;
- }
- buf << "}\n";
-}
-
-void make_narg_call_with_return(const unsigned N, const std::string& class_name,
- std::ostringstream& buf, int indent_level, const FunctionDecl* fdecl) {
- // Make a code string that follows this pattern:
- //
- // if (ret) {
- // new (ret) (return_type) ((class_name*)obj)->func(args...);
- // }
- // else {
- // ((class_name*)obj)->func(args...);
- // }
- //
- if (const CXXConstructorDecl* CD = dyn_cast<CXXConstructorDecl>(fdecl)) {
- (void) CD;
- make_narg_ctor_with_return(N, class_name, buf, indent_level, fdecl);
- return;
- }
- QualType QT = fdecl->getResultType().getCanonicalType();
- if (QT->isVoidType()) {
- std::ostringstream typedefbuf;
- std::ostringstream callbuf;
- for (int i = 0; i < indent_level; ++i) {
- callbuf << indent_string;
- }
- make_narg_call(N, typedefbuf, callbuf, class_name, indent_level, fdecl);
- callbuf << ";\n";
- for (int i = 0; i < indent_level; ++i) {
- callbuf << indent_string;
- }
- callbuf << "return;\n";
- buf << typedefbuf.str() << callbuf.str();
- }
- else {
- for (int i = 0; i < indent_level; ++i) {
- buf << indent_string;
- }
- buf << "if (ret) {\n";
- ++indent_level;
- {
- std::ostringstream typedefbuf;
- std::ostringstream callbuf;
- //
- // Write the placement part of the placement new.
- //
- for (int i = 0; i < indent_level; ++i) {
- callbuf << indent_string;
- }
- callbuf << "new (ret) ";
- std::string type_name;
- bool isReference = false;
- int ptrCnt = 0;
- collect_type_info(QT, typedefbuf, callbuf, type_name,
- isReference, ptrCnt, indent_level, false, fdecl);
- //
- // Write the type part of the placement new.
- //
- if (isReference) {
- std::string stars;
- for (int j = 0; j < ptrCnt; ++j) {
- stars.push_back('*');
- }
- callbuf << "(" << type_name.c_str() << stars << "*) (&";
- }
- else if (ptrCnt) {
- std::string stars;
- for (int j = 0; j < ptrCnt; ++j) {
- stars.push_back('*');
- }
- callbuf << "(" << type_name.c_str() << stars << ") (";
- }
- else {
- callbuf << "(" << type_name.c_str() << ") (";
- }
- //
- // Write the actual function call.
- //
- make_narg_call(N, typedefbuf, callbuf, class_name, indent_level, fdecl);
- //
- // End the placement new.
- //
- callbuf << ");\n";
- for (int i = 0; i < indent_level; ++i) {
- callbuf << indent_string;
- }
- callbuf << "return;\n";
- //
- // Output the whole placement new expression and return statement.
- //
- buf << typedefbuf.str() << callbuf.str();
- }
- --indent_level;
- for (int i = 0; i < indent_level; ++i) {
- buf << indent_string;
- }
- buf << "}\n";
- for (int i = 0; i < indent_level; ++i) {
- buf << indent_string;
- }
- buf << "else {\n";
- ++indent_level;
- {
- std::ostringstream typedefbuf;
- std::ostringstream callbuf;
- for (int i = 0; i < indent_level; ++i) {
- callbuf << indent_string;
- }
- make_narg_call(N, typedefbuf, callbuf, class_name, indent_level, fdecl);
- callbuf << ";\n";
- for (int i = 0; i < indent_level; ++i) {
- callbuf << indent_string;
- }
- callbuf << "return;\n";
- buf << typedefbuf.str() << callbuf.str();
- }
- --indent_level;
- for (int i = 0; i < indent_level; ++i) {
- buf << indent_string;
- }
- buf << "}\n";
- }
-}
-
-static CPPYY_Cling_Wrapper_t make_wrapper(const FunctionDecl* fdecl) {
- ASTContext& Context = fdecl->getASTContext();
- PrintingPolicy Policy(Context.getPrintingPolicy());
- //
- // Get the class or namespace name.
- //
- std::string class_name;
- // if (const TypeDecl* TD = llvm::dyn_cast<TypeDecl>(fdecl->getDeclContext())) {
- // // This is a class, struct, or union member.
- // QualType QT(TD->getTypeForDecl(), 0);
- // ROOT::TMetaUtils::GetFullyQualifiedTypeName(class_name, QT, *gCppyy_Cling);
- // // And drop the default arguments if any (at least until the clang
- // // type printer properly handle template paratemeter that are enumerator).
- // R__DropDefaultArg(class_name);
- // }
- // else
- if (const NamedDecl* ND = llvm::dyn_cast<NamedDecl>(fdecl->getDeclContext())) {
- // This is a namespace member.
- llvm::raw_string_ostream stream(class_name);
- ND->getNameForDiagnostic(stream, Policy, /*Qualified=*/true);
- stream.flush();
- }
- //
- // Check to make sure that we can
- // instantiate and codegen this function.
- //
- bool needInstantiation = false;
- const FunctionDecl* Definition = 0;
- if (!fdecl->isDefined(Definition)) {
- FunctionDecl::TemplatedKind TK = fdecl->getTemplatedKind();
- switch (TK) {
- case FunctionDecl::TK_NonTemplate: {
- // Ordinary function, not a template specialization.
- // Note: This might be ok, the body might be defined
- // in a library, and all we have seen is the
- // header file.
- //print_error("make_wrapper",
- // "cannot make wrapper for a function which is declared but not defined!");
- //return 0;
- break;
- }
- case FunctionDecl::TK_FunctionTemplate: {
- // This decl is actually a function template,
- // not a function at all.
- print_error("make_wrapper", "cannot make wrapper for a function template!");
- return 0;
- }
- case FunctionDecl::TK_MemberSpecialization: {
- // This function is the result of instantiating an ordinary
- // member function of a class template, or of instantiating
- // an ordinary member function of a class member of a class
- // template, or of specializing a member function template
- // of a class template, or of specializing a member function
- // template of a class member of a class template.
- if (!fdecl->isTemplateInstantiation()) {
- // We are either TSK_Undeclared or
- // TSK_ExplicitSpecialization.
- // Note: This might be ok, the body might be defined
- // in a library, and all we have seen is the
- // header file.
- //print_error("make_wrapper",
- // "cannot make wrapper for a function template explicit specialization"
- // " which is declared but not defined!");
- //return 0;
- break;
- }
- const FunctionDecl* Pattern = fdecl->getTemplateInstantiationPattern();
- if (!Pattern) {
- print_error("make_wrapper",
- "cannot make wrapper for a member function instantiation with no pattern!");
- return 0;
- }
- FunctionDecl::TemplatedKind PTK = Pattern->getTemplatedKind();
- TemplateSpecializationKind PTSK =
- Pattern->getTemplateSpecializationKind();
- if (
- // The pattern is an ordinary member function.
- (PTK == FunctionDecl::TK_NonTemplate) ||
- // The pattern is an explicit specialization, and
- // so is not a template.
- ((PTK != FunctionDecl::TK_FunctionTemplate) &&
- ((PTSK == TSK_Undeclared) ||
- (PTSK == TSK_ExplicitSpecialization)))
- ) {
- // Note: This might be ok, the body might be defined
- // in a library, and all we have seen is the
- // header file.
- break;
- }
- else if (!Pattern->hasBody()) {
- print_error("make_wrapper",
- "cannot make wrapper for a member function instantiation with no body!");
- return 0;
- }
- if (fdecl->isImplicitlyInstantiable()) {
- needInstantiation = true;
- }
- break;
- }
- case FunctionDecl::TK_FunctionTemplateSpecialization: {
- // This function is the result of instantiating a function
- // template or possibly an explicit specialization of a
- // function template. Could be a namespace scope function or a
- // member function.
- if (!fdecl->isTemplateInstantiation()) {
- // We are either TSK_Undeclared or
- // TSK_ExplicitSpecialization.
- // Note: This might be ok, the body might be defined
- // in a library, and all we have seen is the
- // header file.
- //print_error("make_wrapper",
- // "Cannot make wrapper for a function template "
- // "explicit specialization which is declared but not defined!");
- //return 0;
- break;
- }
- const FunctionDecl* Pattern = fdecl->getTemplateInstantiationPattern();
- if (!Pattern) {
- print_error("make_wrapper",
- "cannot make wrapper for a function template instantiation with no pattern!");
- return 0;
- }
- FunctionDecl::TemplatedKind PTK = Pattern->getTemplatedKind();
- TemplateSpecializationKind PTSK =
- Pattern->getTemplateSpecializationKind();
- if (
- // The pattern is an ordinary member function.
- (PTK == FunctionDecl::TK_NonTemplate) ||
- // The pattern is an explicit specialization, and
- // so is not a template.
- ((PTK != FunctionDecl::TK_FunctionTemplate) &&
- ((PTSK == TSK_Undeclared) ||
- (PTSK == TSK_ExplicitSpecialization)))
- ) {
- // Note: This might be ok, the body might be defined
- // in a library, and all we have seen is the
- // header file.
- break;
- }
- if (!Pattern->hasBody()) {
- print_error("make_wrapper",
- "cannot make wrapper for a function template instantiation with no body!");
- return 0;
- }
- if (fdecl->isImplicitlyInstantiable()) {
- needInstantiation = true;
- }
- break;
- }
- case FunctionDecl::TK_DependentFunctionTemplateSpecialization: {
- // This function is the result of instantiating or
- // specializing a member function of a class template,
- // or a member function of a class member of a class template,
- // or a member function template of a class template, or a
- // member function template of a class member of a class
- // template where at least some part of the function is
- // dependent on a template argument.
- if (!fdecl->isTemplateInstantiation()) {
- // We are either TSK_Undeclared or
- // TSK_ExplicitSpecialization.
- // Note: This might be ok, the body might be defined
- // in a library, and all we have seen is the
- // header file.
- //print_error("make_wrapper",
- // "Cannot make wrapper for a dependent function template explicit specialization
- // " which is declared but not defined!");
- //return 0;
- break;
- }
- const FunctionDecl* Pattern = fdecl->getTemplateInstantiationPattern();
- if (!Pattern) {
- print_error("make_wrapper",
- "cannot make wrapper for a dependent function template instantiation with no pattern!");
- return 0;
- }
- FunctionDecl::TemplatedKind PTK = Pattern->getTemplatedKind();
- TemplateSpecializationKind PTSK =
- Pattern->getTemplateSpecializationKind();
- if (
- // The pattern is an ordinary member function.
- (PTK == FunctionDecl::TK_NonTemplate) ||
- // The pattern is an explicit specialization, and
- // so is not a template.
- ((PTK != FunctionDecl::TK_FunctionTemplate) &&
- ((PTSK == TSK_Undeclared) ||
- (PTSK == TSK_ExplicitSpecialization)))
- ) {
- // Note: This might be ok, the body might be defined
- // in a library, and all we have seen is the
- // header file.
- break;
- }
- if (!Pattern->hasBody()) {
- print_error("make_wrapper",
- "cannot make wrapper for a dependent function template instantiation with no body!");
- return 0;
- }
- if (fdecl->isImplicitlyInstantiable()) {
- needInstantiation = true;
- }
- break;
- }
- default: {
- // Will only happen if clang implementation changes.
- // Protect ourselves in case that happens.
- print_error("make_wrapper", "unhandled template kind!");
- return 0;
- }
- }
- // We do not set needInstantiation to true in these cases:
- //
- // isInvalidDecl()
- // TSK_Undeclared
- // TSK_ExplicitInstantiationDefinition
- // TSK_ExplicitSpecialization && !getClassScopeSpecializationPattern()
- // TSK_ExplicitInstantiationDeclaration &&
- // getTemplateInstantiationPattern() &&
- // PatternDecl->hasBody() &&
- // !PatternDecl->isInlined()
- //
- // Set it true in these cases:
- //
- // TSK_ImplicitInstantiation
- // TSK_ExplicitInstantiationDeclaration && (!getPatternDecl() ||
- // !PatternDecl->hasBody() || PatternDecl->isInlined())
- //
- }
- if (needInstantiation) {
- clang::FunctionDecl* FDmod = const_cast<clang::FunctionDecl*>(fdecl);
- clang::Sema& S = gCppyy_Cling->getSema();
- // Could trigger deserialization of decls.
- cling::Interpreter::PushTransactionRAII RAII(gCppyy_Cling);
- S.InstantiateFunctionDefinition(SourceLocation(), FDmod,
- /*Recursive=*/ true,
- /*DefinitionRequired=*/ true);
- if (!fdecl->isDefined(Definition)) {
- print_error("make_wrapper", "failed to force template instantiation!");
- return 0;
- }
- }
- if (Definition) {
- FunctionDecl::TemplatedKind TK = Definition->getTemplatedKind();
- switch (TK) {
- case FunctionDecl::TK_NonTemplate: {
- // Ordinary function, not a template specialization.
- if (Definition->isDeleted()) {
- print_error("make_wrapper", "cannot make wrapper for a deleted function!");
- return 0;
- }
- else if (Definition->isLateTemplateParsed()) {
- print_error("make_wrapper",
- "Cannot make wrapper for a late template parsed function!");
- return 0;
- }
- //else if (Definition->isDefaulted()) {
- // // Might not have a body, but we can still use it.
- //}
- //else {
- // // Has a body.
- //}
- break;
- }
- case FunctionDecl::TK_FunctionTemplate: {
- // This decl is actually a function template,
- // not a function at all.
- print_error("make_wrapper", "cannot make wrapper for a function template!");
- return 0;
- }
- case FunctionDecl::TK_MemberSpecialization: {
- // This function is the result of instantiating an ordinary
- // member function of a class template or of a member class
- // of a class template.
- if (Definition->isDeleted()) {
- print_error("make_wrapper",
- "cannot make wrapper for a deleted member function of a specialization!");
- return 0;
- }
- else if (Definition->isLateTemplateParsed()) {
- print_error("make_wrapper",
- "cannot make wrapper for a late template parsed member function of a specialization!");
- return 0;
- }
- //else if (Definition->isDefaulted()) {
- // // Might not have a body, but we can still use it.
- //}
- //else {
- // // Has a body.
- //}
- break;
- }
- case FunctionDecl::TK_FunctionTemplateSpecialization: {
- // This function is the result of instantiating a function
- // template or possibly an explicit specialization of a
- // function template. Could be a namespace scope function or a
- // member function.
- if (Definition->isDeleted()) {
- print_error("make_wrapper",
- "cannot make wrapper for a deleted function template specialization!");
- return 0;
- }
- else if (Definition->isLateTemplateParsed()) {
- print_error("make_wrapper",
- "cannot make wrapper for a late template parsed function template specialization!");
- return 0;
- }
- //else if (Definition->isDefaulted()) {
- // // Might not have a body, but we can still use it.
- //}
- //else {
- // // Has a body.
- //}
- break;
- }
- case FunctionDecl::TK_DependentFunctionTemplateSpecialization: {
- // This function is the result of instantiating or
- // specializing a member function of a class template,
- // or a member function of a class member of a class template,
- // or a member function template of a class template, or a
- // member function template of a class member of a class
- // template where at least some part of the function is
- // dependent on a template argument.
- if (Definition->isDeleted()) {
- print_error("make_wrapper",
- "cannot make wrapper for a deleted dependent function template specialization!");
- return 0;
- }
- else if (Definition->isLateTemplateParsed()) {
- print_error("make_wrapper",
- "cannot make wrapper for a late template parsed "
- "dependent function template specialization!");
- return 0;
- }
- //else if (Definition->isDefaulted()) {
- // // Might not have a body, but we can still use it.
- //}
- //else {
- // // Has a body.
- //}
- break;
- }
- default: {
- // Will only happen if clang implementation changes.
- // Protect ourselves in case that happens.
- print_error("make_wrapper", "unhandled template kind!");
- return 0;
- }
- }
- }
- unsigned min_args = fdecl->getMinRequiredArguments();
- unsigned num_params = fdecl->getNumParams();
- //
- // Make the wrapper name.
- //
- std::string wrapper_name;
- {
- std::ostringstream buf;
- buf << "__cf";
- //const NamedDecl* ND = llvm::dyn_cast<NamedDecl>(fdecl);
- //std::string mn;
- //gCppyy_Cling->maybeMangleDeclName(ND, mn);
- //buf << '_' << mn;
- buf << '_' << wrapper_serial++;
- wrapper_name = buf.str();
- }
- //
- // Write the wrapper code.
- // FIXME: this should be synthesized into the AST!
- //
- int indent_level = 0;
- std::ostringstream buf;
- buf << "__attribute__((used)) ";
- buf << "extern \"C\" void ";
- buf << wrapper_name;
- buf << "(void* obj, int nargs, void** args, void* ret)\n";
- buf << "{\n";
- ++indent_level;
- if (min_args == num_params) {
- // No parameters with defaults.
- make_narg_call_with_return(num_params, class_name, buf, indent_level, fdecl);
- }
- else {
- // We need one function call clause compiled for every
- // possible number of arguments per call.
- for (unsigned N = min_args; N <= num_params; ++N) {
- for (int i = 0; i < indent_level; ++i) {
- buf << indent_string;
- }
- buf << "if (nargs == " << N << ") {\n";
- ++indent_level;
- make_narg_call_with_return(N, class_name, buf, indent_level, fdecl);
- --indent_level;
- for (int i = 0; i < indent_level; ++i) {
- buf << indent_string;
- }
- buf << "}\n";
- }
- }
- --indent_level;
- buf << "}\n";
- //
- // Compile the wrapper code.
- //
- std::string wrapper_code(buf.str());
- std::cout << " CREATED WRAPPER: " << std::endl;
- std::cout << wrapper_code << std::endl;
- void* wrapper = gCppyy_Cling->compileFunction(
- wrapper_name, wrapper_code, false /*ifUnique*/, true /*withAcessControl*/);
- if (wrapper)
- s_wrappers.insert(std::make_pair((cppyy_method_t)fdecl, (CPPYY_Cling_Wrapper_t)wrapper));
- return (CPPYY_Cling_Wrapper_t)wrapper;
+void cppyy_free(void* ptr) {
+ free(ptr);
+}
+
+cppyy_object_t cppyy_charp2stdstring(const char* str){
+ return (cppyy_object_t)new std::string(str);
}
+
+cppyy_object_t cppyy_stdstring2stdstring(cppyy_object_t ptr){
+ return (cppyy_object_t)new std::string(*(std::string*)ptr);
+}
+
+} // end C-linkage wrappers
diff --git a/pypy/module/cppyy/test/Makefile b/pypy/module/cppyy/test/Makefile
index e70a5c9050..20ff6fe58a 100644
--- a/pypy/module/cppyy/test/Makefile
+++ b/pypy/module/cppyy/test/Makefile
@@ -60,7 +60,7 @@ else ifeq ($(DUMMY),t)
else # reflex
%Dict.so: %_rflx.cpp %.cxx
- g++ -o $@ $^ -shared -lReflex $(cppflags) $(cppflags2)
+ g++ -o $@ $^ -shared -std=c++14 $(cppflags) $(cppflags2)
%_rflx.cpp: %.h %.xml
$(genreflex) $< $(genreflexflags) --selection=$*.xml --rootmap=$*Dict.rootmap --rootmap-lib=$*Dict.so
@@ -72,10 +72,10 @@ ifeq ($(DUMMY),)
# TODO: methptrgetter causes these tests to crash, so don't use it for now
std_streamsDict.so: std_streams.cxx std_streams.h std_streams.xml
$(genreflex) std_streams.h --selection=std_streams.xml
- g++ -o $@ std_streams_rflx.cpp std_streams.cxx -shared -lReflex $(cppflags) $(cppflags2)
+ g++ -o $@ std_streams_rflx.cpp std_streams.cxx -shared -std=c++14 $(cppflags) $(cppflags2)
endif
endif
.PHONY: clean
clean:
- -rm -f $(dicts) $(subst .so,.rootmap,$(dicts)) $(wildcard *_cint.h)
+ -rm -f $(dicts) $(subst .so,.rootmap,$(dicts)) $(subst Dict.so,_rflx_rdict.pcm,$(dicts)) $(wildcard *_cint.h)
diff --git a/pypy/module/cppyy/test/advancedcpp.xml b/pypy/module/cppyy/test/advancedcpp.xml
index 82fa9a5347..9ebde7e228 100644
--- a/pypy/module/cppyy/test/advancedcpp.xml
+++ b/pypy/module/cppyy/test/advancedcpp.xml
@@ -20,7 +20,7 @@
<class pattern="T3<*>" />
<namespace name="a_ns" />
- <namespace pattern="a_ns::*" />
+ <namespace name="a_ns::d_ns" />
<class pattern="a_ns::*" />
<variable name="a_ns::g_a" />
<function name="a_ns::get_g_a" />
diff --git a/pypy/module/cppyy/test/advancedcpp2.xml b/pypy/module/cppyy/test/advancedcpp2.xml
index 799feedcfa..43925d1039 100644
--- a/pypy/module/cppyy/test/advancedcpp2.xml
+++ b/pypy/module/cppyy/test/advancedcpp2.xml
@@ -1,7 +1,7 @@
<lcgdict>
<namespace name="a_ns" />
- <namespace pattern="a_ns::*" />
+ <namespace name="a_ns::d_ns" />
<class pattern="a_ns::*" />
<variable name="a_ns::g_g" />
<function name="a_ns::get_g_g" />
diff --git a/pypy/module/cppyy/test/stltypes.xml b/pypy/module/cppyy/test/stltypes.xml
index 55fa4bf980..4c06c7d406 100644
--- a/pypy/module/cppyy/test/stltypes.xml
+++ b/pypy/module/cppyy/test/stltypes.xml
@@ -3,18 +3,18 @@
<namespace name="std" />
<class pattern="std::vector<*>" />
- <class pattern="std::vector<*>::iterator" />
- <class pattern="std::vector<*>::const_iterator" />
+ <!-- <class pattern="std::vector<*>::iterator" />
+ <class pattern="std::vector<*>::const_iterator" /> -->
<class pattern="std::list<*>" />
- <class pattern="std::list<*>::iterator" />
+ <!-- <class pattern="std::list<*>::iterator" />
<class pattern="std::list<*>::const_iterator" />
- <class name="std::__detail::_List_node_base" />
+ <class name="std::__detail::_List_node_base" /> -->
<class pattern="std::map<*>" />
<class pattern="std::pair<*>" />
- <class pattern="std::map<*>::iterator" />
- <class pattern="std::map<*>::const_iterator" />
+ <!-- <class pattern="std::map<*>::iterator" />
+ <class pattern="std::map<*>::const_iterator" /> -->
<class pattern="__gnu_cxx::__normal_iterator<*>" />
diff --git a/pypy/module/cppyy/test/test_cppyy.py b/pypy/module/cppyy/test/test_cppyy.py
index 88aed58c2b..3d400746e2 100644
--- a/pypy/module/cppyy/test/test_cppyy.py
+++ b/pypy/module/cppyy/test/test_cppyy.py
@@ -4,7 +4,7 @@ from pypy.module.cppyy import interp_cppyy, executor
currpath = py.path.local(__file__).dirpath()
-test_dct = str(currpath.join("example01Dict.so"))
+test_dct = str(currpath.join("example01_rflx_rdict.pcm"))#example01Dict.so"))
def setup_module(mod):
if sys.platform == 'win32':