def get_converter(space, name, default): # The matching of the name to a converter should follow: # 1) full, exact match # 1a) const-removed match # 2) match of decorated, unqualified type # 3) accept ref as pointer (for the stubs, const& can be # by value, but that does not work for the ffi path) # 4) generalized cases (covers basically all user classes) # 5) void converter, which fails on use name = capi.c_resolve_name(space, name) # 1) full, exact match try: return _converters[name](space, default) except KeyError: pass # 1a) const-removed match try: return _converters[helper.remove_const(name)](space, default) except KeyError: pass # 2) match of decorated, unqualified type compound = helper.compound(name) clean_name = capi.c_resolve_name(space, helper.clean_type(name)) try: # array_index may be negative to indicate no size or no size found array_size = helper.array_size(name) return _a_converters[clean_name + compound](space, array_size) except KeyError: pass # 3) TODO: accept ref as pointer # 4) generalized cases (covers basically all user classes) from pypy.module.cppyy import interp_cppyy cppclass = interp_cppyy.scope_byname(space, clean_name) if cppclass: # type check for the benefit of the annotator from pypy.module.cppyy.interp_cppyy import W_CPPClass cppclass = space.interp_w(W_CPPClass, cppclass, can_be_None=False) if compound == "*": return InstancePtrConverter(space, cppclass) elif compound == "&": return InstanceRefConverter(space, cppclass) elif compound == "**": return InstancePtrPtrConverter(space, cppclass) elif compound == "": return InstanceConverter(space, cppclass) elif capi.c_is_enum(space, clean_name): return _converters['unsigned'](space, default) # 5) void converter, which fails on use # # return a void converter here, so that the class can be build even # when some types are unknown; this overload will simply fail on use return VoidConverter(space, name)
def get_converter(space, name, default): # The matching of the name to a converter should follow: # 1) full, exact match # 1a) const-removed match # 2) match of decorated, unqualified type # 3) accept ref as pointer (for the stubs, const& can be # by value, but that does not work for the ffi path) # 4) generalized cases (covers basically all user classes) # 5) void converter, which fails on use name = capi.c_resolve_name(space, name) # 1) full, exact match try: return _converters[name](space, default) except KeyError: pass # 1a) const-removed match try: return _converters[helper.remove_const(name)](space, default) except KeyError: pass # 2) match of decorated, unqualified type compound = helper.compound(name) clean_name = capi.c_resolve_name(space, helper.clean_type(name)) try: # array_index may be negative to indicate no size or no size found array_size = helper.array_size(name) return _a_converters[clean_name+compound](space, array_size) except KeyError: pass # 3) TODO: accept ref as pointer # 4) generalized cases (covers basically all user classes) from pypy.module.cppyy import interp_cppyy cppclass = interp_cppyy.scope_byname(space, clean_name) if cppclass: # type check for the benefit of the annotator from pypy.module.cppyy.interp_cppyy import W_CPPClass cppclass = space.interp_w(W_CPPClass, cppclass, can_be_None=False) if compound == "*": return InstancePtrConverter(space, cppclass) elif compound == "&": return InstanceRefConverter(space, cppclass) elif compound == "**": return InstancePtrPtrConverter(space, cppclass) elif compound == "": return InstanceConverter(space, cppclass) elif capi.c_is_enum(space, clean_name): return _converters['unsigned'](space, default) # 5) void converter, which fails on use # # return a void converter here, so that the class can be build even # when some types are unknown; this overload will simply fail on use return VoidConverter(space, name)
def get_executor(space, name): # Matching of 'name' to an executor factory goes through up to four levels: # 1) full, qualified match # 2) drop '&': by-ref is pretty much the same as by-value, python-wise # 3) types/classes, either by ref/ptr or by value # 4) additional special cases # # If all fails, a default is used, which can be ignored at least until use. name = capi.c_resolve_name(space, name) # 1) full, qualified match try: return _executors[name](space, None) except KeyError: pass compound = helper.compound(name) clean_name = capi.c_resolve_name(space, helper.clean_type(name)) # 1a) clean lookup try: return _executors[clean_name + compound](space, None) except KeyError: pass # 2) drop '&': by-ref is pretty much the same as by-value, python-wise if compound and compound[len(compound) - 1] == '&': # TODO: this does not actually work with Reflex (?) try: return _executors[clean_name](space, None) except KeyError: pass # 3) types/classes, either by ref/ptr or by value from pypy.module.cppyy import interp_cppyy cppclass = interp_cppyy.scope_byname(space, clean_name) if cppclass: # type check for the benefit of the annotator from pypy.module.cppyy.interp_cppyy import W_CPPClass cppclass = space.interp_w(W_CPPClass, cppclass, can_be_None=False) if compound == '': return InstanceExecutor(space, cppclass) elif compound == '*' or compound == '&': return InstancePtrExecutor(space, cppclass) elif compound == '**' or compound == '*&': return InstancePtrPtrExecutor(space, cppclass) elif capi.c_is_enum(space, clean_name): return _executors['unsigned int'](space, None) # 4) additional special cases if compound == '*': return _executors['void*']( space, None) # allow at least passing of the pointer # currently used until proper lazy instantiation available in interp_cppyy return FunctionExecutor(space, None)
def get_executor(space, name): # Matching of 'name' to an executor factory goes through up to four levels: # 1) full, qualified match # 2) drop '&': by-ref is pretty much the same as by-value, python-wise # 3) types/classes, either by ref/ptr or by value # 4) additional special cases # # If all fails, a default is used, which can be ignored at least until use. name = capi.c_resolve_name(space, name) # 1) full, qualified match try: return _executors[name](space, None) except KeyError: pass compound = helper.compound(name) clean_name = capi.c_resolve_name(space, helper.clean_type(name)) # 1a) clean lookup try: return _executors[clean_name+compound](space, None) except KeyError: pass # 2) drop '&': by-ref is pretty much the same as by-value, python-wise if compound and compound[len(compound)-1] == '&': # TODO: this does not actually work with Reflex (?) try: return _executors[clean_name](space, None) except KeyError: pass # 3) types/classes, either by ref/ptr or by value from pypy.module.cppyy import interp_cppyy cppclass = interp_cppyy.scope_byname(space, clean_name) if cppclass: # type check for the benefit of the annotator from pypy.module.cppyy.interp_cppyy import W_CPPClass cppclass = space.interp_w(W_CPPClass, cppclass, can_be_None=False) if compound == '': return InstanceExecutor(space, cppclass) elif compound == '*' or compound == '&': return InstancePtrExecutor(space, cppclass) elif compound == '**' or compound == '*&': return InstancePtrPtrExecutor(space, cppclass) elif capi.c_is_enum(space, clean_name): return _executors['unsigned int'](space, None) # 4) additional special cases if compound == '*': return _executors['void*'](space, None) # allow at least passing of the pointer # currently used until proper lazy instantiation available in interp_cppyy return FunctionExecutor(space, None)
def scope_byname(space, name): true_name = capi.c_resolve_name(name) state = space.fromcache(State) try: return state.cppscope_cache[true_name] except KeyError: pass opaque_handle = capi.c_get_scope_opaque(true_name) assert lltype.typeOf(opaque_handle) == capi.C_SCOPE if opaque_handle: final_name = capi.c_final_name(opaque_handle) if capi.c_is_namespace(opaque_handle): cppscope = W_CPPNamespace(space, final_name, opaque_handle) elif capi.c_has_complex_hierarchy(opaque_handle): cppscope = W_ComplexCPPClass(space, final_name, opaque_handle) else: cppscope = W_CPPClass(space, final_name, opaque_handle) state.cppscope_cache[name] = cppscope cppscope._find_methods() cppscope._find_datamembers() return cppscope return None
def call(self, cppthis, args_w): assert lltype.typeOf(cppthis) == capi.C_OBJECT for i in range(len(args_w)): try: s = self.space.str_w(args_w[i]) except OperationError: s = self.space.str_w(self.space.getattr(args_w[i], self.space.wrap('__name__'))) s = capi.c_resolve_name(self.space, s) if s != self.templ_args[i]: raise OperationError(self.space.w_TypeError, self.space.wrap( "non-matching template (got %s where %s expected" % (s, self.templ_args[i]))) return W_CPPBoundMethod(cppthis, self)
def map_operator_name(space, cppname, nargs, result_type): from pypy.module.cppyy import capi if cppname[0:8] == "operator": op = cppname[8:].strip(' ') # look for known mapping try: return _operator_mappings[op] except KeyError: pass # return-type dependent mapping if op == "[]": if result_type.find("const") != 0: cpd = compound(result_type) if cpd and cpd[len(cpd)-1] == "&": return "__setitem__" return "__getitem__" # a couple more cases that depend on whether args were given if op == "*": # dereference (not python) vs. multiplication return nargs and "__mul__" or "__deref__" if op == "+": # unary positive vs. binary addition return nargs and "__add__" or "__pos__" if op == "-": # unary negative vs. binary subtraction return nargs and "__sub__" or "__neg__" if op == "++": # prefix v.s. postfix increment (not python) return nargs and "__postinc__" or "__preinc__" if op == "--": # prefix v.s. postfix decrement (not python) return nargs and "__postdec__" or "__predec__" # operator could have been a conversion using a typedef (this lookup # is put at the end only as it is unlikely and may trigger unwanted # errors in class loaders in the backend, because a typical operator # name is illegal as a class name) true_op = capi.c_resolve_name(space, op) try: return _operator_mappings[true_op] except KeyError: pass # might get here, as not all operator methods handled (although some with # no python equivalent, such as new, delete, etc., are simply retained) # TODO: perhaps absorb or "pythonify" these operators? return cppname
def resolve_name(space, name): return space.wrap(capi.c_resolve_name(name))
def ttree_getattr(space, w_self, args_w): """Specialized __getattr__ for TTree's that allows switching on/off the reading of individual branchs.""" from pypy.module.cppyy import interp_cppyy tree = space.interp_w(interp_cppyy.W_CPPInstance, w_self) space = tree.space # holds the class cache in State # prevent recursion attr = space.str_w(args_w[0]) if attr and attr[0] == '_': raise OperationError(space.w_AttributeError, args_w[0]) # try the saved cdata (for builtin types) try: w_cdata = space.getattr(w_self, space.wrap('_' + attr)) from pypy.module._cffi_backend import cdataobj cdata = space.interp_w(cdataobj.W_CData, w_cdata, can_be_None=False) return cdata.convert_to_object() except OperationError: pass # setup branch as a data member and enable it for reading w_branch = space.call_method(w_self, "GetBranch", args_w[0]) if not space.is_true(w_branch): raise OperationError(space.w_AttributeError, args_w[0]) activate_branch(space, w_branch) # figure out from where we're reading entry = space.r_longlong_w(space.call_method(w_self, "GetReadEntry")) if entry == -1: entry = 0 # setup cache structure w_klassname = space.call_method(w_branch, "GetClassName") if space.is_true(w_klassname): # some instance klass = interp_cppyy.scope_byname(space, space.str_w(w_klassname)) w_obj = klass.construct() # 0x10000 = kDeleteObject; reset because we own the object space.call_method(w_branch, "ResetBit", space.wrap(0x10000)) space.call_method(w_branch, "SetObject", w_obj) space.call_method(w_branch, "GetEntry", space.wrap(entry)) space.setattr(w_self, args_w[0], w_obj) return w_obj else: # builtin data w_leaf = space.call_method(w_self, "GetLeaf", args_w[0]) space.call_method(w_branch, "GetEntry", space.wrap(entry)) # location w_address = space.call_method(w_leaf, "GetValuePointer") buf = space.getarg_w('s*', w_address) from pypy.module._rawffi import buffer assert isinstance(buf, buffer.RawFFIBuffer) address = rffi.cast(rffi.CCHARP, buf.datainstance.ll_buffer) # placeholder w_typename = space.call_method(w_leaf, "GetTypeName") from pypy.module.cppyy import capi typename = capi.c_resolve_name(space, space.str_w(w_typename)) if typename == 'bool': typename = '_Bool' w_address = space.call_method(w_leaf, "GetValuePointer") from pypy.module._cffi_backend import cdataobj, newtype cdata = cdataobj.W_CData(space, address, newtype.new_primitive_type(space, typename)) # cache result space.setattr(w_self, space.wrap('_' + attr), space.wrap(cdata)) return space.getattr(w_self, args_w[0])
def ttree_getattr(space, w_self, args_w): """Specialized __getattr__ for TTree's that allows switching on/off the reading of individual branchs.""" from pypy.module.cppyy import interp_cppyy tree = space.interp_w(interp_cppyy.W_CPPInstance, w_self) space = tree.space # holds the class cache in State # prevent recursion attr = space.str_w(args_w[0]) if attr and attr[0] == '_': raise OperationError(space.w_AttributeError, args_w[0]) # try the saved cdata (for builtin types) try: w_cdata = space.getattr(w_self, space.wrap('_'+attr)) from pypy.module._cffi_backend import cdataobj cdata = space.interp_w(cdataobj.W_CData, w_cdata, can_be_None=False) return cdata.convert_to_object() except OperationError: pass # setup branch as a data member and enable it for reading w_branch = space.call_method(w_self, "GetBranch", args_w[0]) if not space.is_true(w_branch): raise OperationError(space.w_AttributeError, args_w[0]) activate_branch(space, w_branch) # figure out from where we're reading entry = space.int_w(space.call_method(w_self, "GetReadEntry")) if entry == -1: entry = 0 # setup cache structure w_klassname = space.call_method(w_branch, "GetClassName") if space.is_true(w_klassname): # some instance klass = interp_cppyy.scope_byname(space, space.str_w(w_klassname)) w_obj = klass.construct() space.call_method(w_branch, "SetObject", w_obj) space.call_method(w_branch, "GetEntry", space.wrap(entry)) space.setattr(w_self, args_w[0], w_obj) return w_obj else: # builtin data w_leaf = space.call_method(w_self, "GetLeaf", args_w[0]) space.call_method(w_branch, "GetEntry", space.wrap(entry)) # location w_address = space.call_method(w_leaf, "GetValuePointer") buf = space.buffer_w(w_address) from pypy.module._rawffi import buffer assert isinstance(buf, buffer.RawFFIBuffer) address = rffi.cast(rffi.CCHARP, buf.datainstance.ll_buffer) # placeholder w_typename = space.call_method(w_leaf, "GetTypeName" ) from pypy.module.cppyy import capi typename = capi.c_resolve_name(space, space.str_w(w_typename)) if typename == 'bool': typename = '_Bool' w_address = space.call_method(w_leaf, "GetValuePointer") from pypy.module._cffi_backend import cdataobj, newtype cdata = cdataobj.W_CData(space, address, newtype.new_primitive_type(space, typename)) # cache result space.setattr(w_self, space.wrap('_'+attr), space.wrap(cdata)) return space.getattr(w_self, args_w[0])