Author: Wim Lavrijsen <wlavrij...@lbl.gov> Branch: cling-support Changeset: r85418:1e669815cd70 Date: 2016-06-27 13:59 -0700 http://bitbucket.org/pypy/pypy/changeset/1e669815cd70/
Log: From Aditi: first stab at new Cling backend, based off the C++ Cppyy.cxx diff too long, truncating to 2000 out of 3541 lines diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -77,3 +77,5 @@ ^.hypothesis/ ^release/ ^rpython/_cache$ + +pypy/module/cppyy/.+/*\.pcm diff --git a/pypy/module/cppyy/bench/Makefile b/pypy/module/cppyy/bench/Makefile --- a/pypy/module/cppyy/bench/Makefile +++ b/pypy/module/cppyy/bench/Makefile @@ -26,4 +26,4 @@ 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 --- a/pypy/module/cppyy/capi/__init__.py +++ b/pypy/module/cppyy/capi/__init__.py @@ -9,8 +9,8 @@ # 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 --- 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 --- a/pypy/module/cppyy/capi/cling_capi.py +++ b/pypy/module/cppyy/capi/cling_capi.py @@ -16,7 +16,8 @@ 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 @@ 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 --- a/pypy/module/cppyy/converter.py +++ b/pypy/module/cppyy/converter.py @@ -735,7 +735,7 @@ 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 @@ _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 @@ (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 --- /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 --- 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 --- /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 --- a/pypy/module/cppyy/src/clingcwrapper.cxx +++ b/pypy/module/cppyy/src/clingcwrapper.cxx @@ -1,1810 +1,1364 @@ -#include "cppyy.h" -#include "clingcwrapper.h" +// Bindings +#include "capi.h" +#include "cpp_cppyy.h" +#include "callcontext.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 * - *************************************************************************/ +// 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" -#include <stdint.h> +// Standard +#include <assert.h> +#include <map> +#include <set> +#include <sstream> -#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" +// temp +#include <iostream> +typedef PyROOT::TParameter TParameter; +// --temp -#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" +// small number that allows use of stack for argument passing +const int SMALL_ARGS_N = 8; -#include <iostream> -#include <map> -#include <string> -#include <sstream> -#include <vector> +// 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; -#include <stdlib.h> -#include <string.h> -#include <unistd.h> +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"); - - // TODO: get this from env - cling_args_storage.push_back("-I/home/wlavrijsen/rootdev/root/etc"); - - 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()); - - // 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); - - // fInterpreter->installLazyFunctionCreator(llvmLazyFunctionCreator); - - { - // R__LOCKGUARD(gInterpreterMutex); - gCppyy_Cling->AddIncludePath("/home/wlavrijsen/rootdev/root/etc/cling"); - gCppyy_Cling->AddIncludePath("."); - } - - // 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); - - gCppyy_Cling->enableDynamicLookup(); - } -} _init; - -typedef std::map<std::string, cppyy_scope_t> NamedHandles_t; -static NamedHandles_t s_named; - -struct SimpleScope { - std::vector<FunctionDecl*> m_methods; - std::vector<Decl*> m_data; -}; - -typedef std::map<cppyy_scope_t, SimpleScope*> Scopes_t; -static Scopes_t s_scopes; - -typedef std::map<cppyy_method_t, CPPYY_Cling_Wrapper_t> Wrappers_t; -static Wrappers_t s_wrappers; + ~ApplicationStarter() { + for ( auto ifunc : g_method2callfunc ) + gInterpreter->CallFunc_Delete( ifunc.second ); + } +} _applicationStarter; } // unnamed namespace - -/* local helpers --------------------------------------------------------- */ -static inline void print_error(const std::string& where, const std::string& what) { - std::cerr << where << ": " << what << std::endl; +// 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 ]; } -static inline char* cppstring_to_cstring(const std::string& name) { +// 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; +} + +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; +} + +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; } -static inline SimpleScope* scope_from_handle(cppyy_type_t handle) { - return s_scopes[(cppyy_scope_t)handle]; + +// 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(); } -static inline std::string qualtype_to_string(const QualType& qt, const ASTContext& atx) { - std::string result; - - 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::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 ""; } -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; +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() ); + + TDataType* dt = gROOT->GetType( tclean.c_str() ); + if ( dt ) return dt->GetFullTypeName(); + return TClassEdit::ResolveTypedef( tclean.c_str(), true ); } +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; +} + +Cppyy::TCppType_t Cppyy::GetTemplate( const std::string& /* template_name */ ) +{ + return (TCppType_t)0; +} + +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; +} + +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; +} + +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; +} + +// 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; +} + +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(); +} + +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>"; +} + +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)); +} + +cppyy_type_t cppyy_actual_class(cppyy_type_t klass, cppyy_object_t obj) { + return cppyy_type_t(Cppyy::GetActualClass(klass, (void*)obj)); +} + + +/* memory management ------------------------------------------------------ */ +cppyy_object_t cppyy_allocate(cppyy_type_t type) { + return cppyy_object_t(Cppyy::Allocate(type)); +} + +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 -------------------------------------------- */ - -// 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 - - -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_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); } - - -cppyy_methptrgetter_t cppyy_get_methptr_getter(cppyy_type_t /* handle */, cppyy_index_t /* method_index */) { - return (cppyy_methptrgetter_t)0; +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_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_enum(const char* /* type_name */) { - return 0; -} - - -/* 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>"); +int cppyy_is_namespace(cppyy_scope_t scope) { + return (int)Cppyy::IsNamespace(scope); } -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; +int cppyy_is_enum(const char* type_name){ + return (int)Cppyy::IsEnum(type_name); } -/* 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(); +/* class reflection information ------------------------------------------- */ +char* cppyy_final_name(cppyy_type_t type) { + return cppstring_to_cstring(Cppyy::GetFinalName(type)); } -cppyy_index_t cppyy_method_index_at(cppyy_scope_t /* scope */, int imeth) { - return (cppyy_index_t)imeth; +char* cppyy_scoped_final_name(cppyy_type_t type) { + return cppstring_to_cstring(Cppyy::GetScopedFinalName(type)); } -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_has_complex_hierarchy(cppyy_type_t type) { + return (int)Cppyy::HasComplexHierarchy(type); } -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); -} - -int cppyy_method_num_args(cppyy_scope_t /* handle */, cppyy_index_t /* method_index */) { - return 1; +int cppyy_num_bases(cppyy_type_t type) { + return (int)Cppyy::GetNumBases(type); } -int cppyy_method_req_args(cppyy_scope_t handle, cppyy_index_t method_index) { - return cppyy_method_num_args(handle, method_index); +char* cppyy_base_name(cppyy_type_t type, int base_index){ + return cppstring_to_cstring(Cppyy::GetBaseName (type, base_index)); } -char* cppyy_method_arg_type(cppyy_scope_t /* handle */, cppyy_index_t /* method_index */, int /* arg_index */) { - return cppstring_to_cstring("double"); +int cppyy_is_subtype(cppyy_type_t derived, cppyy_type_t base){ + return (int)Cppyy::IsSubtype( derived, base ); } -char* cppyy_method_arg_default(cppyy_scope_t handle, cppyy_index_t method_index, int arg_index) { - return cppstring_to_cstring(""); + +/* 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); } -char* cppyy_method_signature(cppyy_scope_t /* handle */, cppyy_index_t /* method_index */) { - return cppstring_to_cstring("double"); + +/* method/function reflection information --------------------------------- */ +int cppyy_num_methods(cppyy_scope_t scope) { + return (int)Cppyy::GetNumMethods (scope); } -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 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_method_index_at(cppyy_scope_t scope, int imeth) { + return cppyy_index_t(Cppyy::GetMethodIndexAt (scope, imeth)); } - -/* method properties ----------------------------------------------------- */ -int cppyy_is_constructor(cppyy_type_t /* handle */, cppyy_index_t /* method_index */) { - return 0; +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); } -int cppyy_is_staticmethod(cppyy_type_t /* handle */, cppyy_index_t /* method_index */) { - return 1; +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)); +} + +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); +} + +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_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)); +} + +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)); +} + +char* cppyy_method_signature(cppyy_scope_t scope, cppyy_index_t idx) { + return cppstring_to_cstring(Cppyy::GetMethodSignature(scope, idx)); +} + +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); +} + +int cppyy_method_num_template_args(cppyy_scope_t scope, cppyy_index_t idx) { + return (int)Cppyy::GetMethodNumTemplateArgs(scope, idx); +} + +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)); +} + +cppyy_method_t cppyy_get_method(cppyy_scope_t scope, cppyy_index_t idx) { + return cppyy_method_t(Cppyy::GetMethod(scope, idx)); +} + +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 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 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)); +} + +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)); +} + +int cppyy_datamember_index(cppyy_scope_t scope, const char* name) { + return (int)Cppyy::GetDatamemberIndex(scope, name); +} + + + +/* data member properties ------------------------------------------------- */ +int cppyy_is_publicdata(cppyy_type_t type, int datamember_index) { + return (int)Cppyy::IsPublicData(type, datamember_index); +} + +int cppyy_is_staticdata(cppyy_type_t type, int datamember_index) { + return (int)Cppyy::IsStaticData(type, datamember_index); +} + /* misc helpers ----------------------------------------------------------- */ +RPY_EXTERN +void* cppyy_load_dictionary(const char* lib_name) { + return (void*)(gInterpreter->Load(lib_name) == 0); +} + +long long cppyy_strtoll(const char* str) { + return strtoll(str, NULL, 0); +} + +unsigned long long cppyy_strtoull(const char* str) { + return strtoull(str, NULL, 0); +} + void cppyy_free(void* ptr) { free(ptr); } - -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; _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit