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['internal_enum_type_t'](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 test_compound(): assert helper.compound("int*") == "*" assert helper.compound("int* const *&") == "**&" assert helper.compound("std::vector<int>*") == "*" assert helper.compound("unsigned long int[5]") == "[]" assert helper.array_size("unsigned long int[5]") == 5
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) generalized cases (covers basically all user classes) # 3a) smart pointers # 4) void* or void converter (which fails on use) name = capi.c_resolve_name(space, _name) # full, exact match try: return _converters[name](space, default) except KeyError: pass # const-removed match try: return _converters[helper.remove_const(name)](space, default) except KeyError: pass # match of decorated, unqualified type cpd = helper.compound(name) clean_name = capi.c_resolve_name(space, helper.clean_type(name)) try: return _converters[clean_name+cpd](space, default) except KeyError: pass # arrays (array_size may be negative, meaning: no size or no size found) array_size = -1 if cpd == "[]": array_size = helper.array_size(_name) # uses original arg elif cpd == '*' and ':' in default: # this happens for multi-dimensional arrays: those are described as pointers cpd = "[]" splitpos = default.find(':') if 0 < splitpos: # always true, but needed for annotator array_size = int(default[:splitpos]) try: # TODO: using clean_name here drops const (e.g. const char[] will # never be seen this way) return _a_converters[clean_name+cpd](space, array_size) except KeyError: pass # generalized cases (covers basically all user classes) from pypy.module._cppyy import interp_cppyy scope_decl = interp_cppyy.scope_byname(space, clean_name) if scope_decl: from pypy.module._cppyy.interp_cppyy import W_CPPClassDecl clsdecl = space.interp_w(W_CPPClassDecl, scope_decl, can_be_None=False) # check smart pointer type check_smart = capi.c_smartptr_info(space, clean_name) if check_smart[0]: if cpd == '': return SmartPtrConverter(space, clsdecl, check_smart[1], check_smart[2]) elif cpd == '*': return SmartPtrPtrConverter(space, clsdecl, check_smart[1], check_smart[2]) elif cpd == '&': return SmartPtrRefConverter(space, clsdecl, check_smart[1], check_smart[2]) # fall through: can still return smart pointer in non-smart way # type check for the benefit of the annotator if cpd == "*": return InstancePtrConverter(space, clsdecl) elif cpd == "&": return InstanceRefConverter(space, clsdecl) elif cpd == "&&": return InstanceMoveConverter(space, clsdecl) elif cpd in ["**", "*[]", "&*"]: return InstancePtrPtrConverter(space, clsdecl) elif cpd == "[]" and array_size > 0: # default encodes the dimensions dims = default.split(':') return InstanceArrayConverter(space, clsdecl, array_size, dims) elif cpd == "": return InstanceConverter(space, clsdecl) elif "(anonymous)" in name: # special case: enum w/o a type name return _converters["internal_enum_type_t"](space, default) elif "(*)" in name or "::*)" in name: # function pointer pos = name.find("*)") if pos > 0: return FunctionPointerConverter(space, name[pos+2:]) # void* or void converter (which fails on use) if 0 <= cpd.find('*'): return VoidPtrConverter(space, default) # "user knows best" # return a void converter here, so that the class can be build even # when some types are unknown return VoidConverter(space, name) # fails on use
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* or 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) # uses original arg 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 scope_decl = interp_cppyy.scope_byname(space, clean_name) if scope_decl: # type check for the benefit of the annotator from pypy.module._cppyy.interp_cppyy import W_CPPClassDecl clsdecl = space.interp_w(W_CPPClassDecl, scope_decl, can_be_None=False) if compound == "*": return InstancePtrConverter(space, clsdecl) elif compound == "&": return InstanceRefConverter(space, clsdecl) elif compound == "&&": return InstanceMoveConverter(space, clsdecl) elif compound == "**": return InstancePtrPtrConverter(space, clsdecl) elif compound == "": return InstanceConverter(space, clsdecl) elif "(anonymous)" in name: # special case: enum w/o a type name return _converters["internal_enum_type_t"](space, default) elif "(*)" in name or "::*)" in name: # function pointer pos = name.find("*)") if pos > 0: return FunctionPointerConverter(space, name[pos + 2:]) # 5) void* or void converter (which fails on use) if 0 <= compound.find('*'): return VoidPtrConverter(space, default) # "user knows best" # return a void converter here, so that the class can be build even # when some types are unknown return VoidConverter(space, name) # fails on use
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. # original, exact match try: return _executors[name](space, None) except KeyError: pass # resolved, exact match name = capi.c_resolve_name(space, name) try: return _executors[name](space, None) except KeyError: pass compound = helper.compound(name) clean_name = capi.c_resolve_name(space, helper.clean_type(name)) # clean lookup try: return _executors[clean_name + compound](space, None) except KeyError: pass # 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 # 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_CPPClassDecl clsdecl = space.interp_w(W_CPPClassDecl, cppclass, can_be_None=False) # check smart pointer type check_smart = capi.c_smartptr_info(space, clean_name) if check_smart[0]: if compound == '': return SmartPointerExecutor(space, clsdecl, check_smart[1], check_smart[2]) elif compound == '*' or compound == '&': return SmartPointerPtrExecutor(space, clsdecl, check_smart[1], check_smart[2]) # fall through: can still return smart pointer in non-smart way if clean_name.find('std::complex', 0, 12) == 0 and\ (0 < clean_name.find('double') or 0 < clean_name.find('float')): if compound == '': return ComplexExecutor(space, clsdecl) elif compound == '&': return ComplexRefExecutor(space, clsdecl) if compound == '': return InstanceExecutor(space, clsdecl) elif compound == '*' or compound == '&': return InstancePtrExecutor(space, clsdecl) elif compound == '**' or compound == '*&': return InstancePtrPtrExecutor(space, clsdecl) elif "(anonymous)" in name: # special case: enum w/o a type name return _executors["internal_enum_type_t"](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 Executor(space, None)