diff options
author | Wim Lavrijsen <WLavrijsen@lbl.gov> | 2016-06-27 13:59:51 -0700 |
---|---|---|
committer | Wim Lavrijsen <WLavrijsen@lbl.gov> | 2016-06-27 13:59:51 -0700 |
commit | ee291ba1216644e0d995e8e8e9d303786ede0ea9 (patch) | |
tree | 57560015ba79d70b86394d210776dcfa755c7cc6 | |
parent | start of exchanging reflex by cling (diff) | |
download | pypy-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-- | .hgignore | 2 | ||||
-rw-r--r-- | pypy/module/cppyy/bench/Makefile | 2 | ||||
-rw-r--r-- | pypy/module/cppyy/capi/__init__.py | 4 | ||||
-rw-r--r-- | pypy/module/cppyy/capi/builtin_capi.py | 3 | ||||
-rw-r--r-- | pypy/module/cppyy/capi/cling_capi.py | 15 | ||||
-rw-r--r-- | pypy/module/cppyy/converter.py | 5 | ||||
-rw-r--r-- | pypy/module/cppyy/include/cpp_cppyy.h | 143 | ||||
-rw-r--r-- | pypy/module/cppyy/include/cppyy.h | 2 | ||||
-rw-r--r-- | pypy/module/cppyy/src/callcontext.h | 101 | ||||
-rw-r--r-- | pypy/module/cppyy/src/clingcwrapper.cxx | 2922 | ||||
-rw-r--r-- | pypy/module/cppyy/test/Makefile | 6 | ||||
-rw-r--r-- | pypy/module/cppyy/test/advancedcpp.xml | 2 | ||||
-rw-r--r-- | pypy/module/cppyy/test/advancedcpp2.xml | 2 | ||||
-rw-r--r-- | pypy/module/cppyy/test/stltypes.xml | 12 | ||||
-rw-r--r-- | pypy/module/cppyy/test/test_cppyy.py | 2 |
15 files changed, 1518 insertions, 1705 deletions
@@ -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': |