def _init_catches(self): ''' Initialize the catch handler used by all pythran-generated functions ''' # topologically sorted exceptions based on the inheritance hierarchy. # needed because otherwise boost python register_exception handlers # do not catch exception type in the right way # (first valid exception is selected) # Inheritance has to be taken into account in the registration order. exceptions = nx.DiGraph() for function_name, v in functions.iteritems(): for mname, symbol in v: if isinstance(symbol, ConstExceptionIntr): exceptions.add_node( getattr(sys.modules[".".join(mname)], function_name)) # add edges based on class relationships for n in exceptions: if n.__base__ in exceptions: exceptions.add_edge(n.__base__, n) sorted_exceptions = nx.topological_sort(exceptions) self.catches = [ ''' #ifdef PYTHONIC_BUILTIN_{uname}_HPP catch(pythonic::types::{name} & e) {{ PyErr_SetString(PyExc_{name}, pythonic::__builtin__::functor::str{{}}(e.args).c_str()); }} #endif '''.format(name=n.__name__, uname=n.__name__.upper()) for n in sorted_exceptions ] self.catches.append(''' catch(...) { PyErr_SetString(PyExc_RuntimeError, "Something happened on the way to heaven" ); }''')
def _init_catches(self): ''' Initialize the catch handler used by all pythran-generated functions ''' # topologically sorted exceptions based on the inheritance hierarchy. # needed because otherwise boost python register_exception handlers # do not catch exception type in the right way # (first valid exception is selected) # Inheritance has to be taken into account in the registration order. exceptions = nx.DiGraph() for function_name, v in functions.iteritems(): for mname, symbol in v: if isinstance(symbol, ConstExceptionIntr): exceptions.add_node( getattr(sys.modules[".".join(mname)], function_name)) # add edges based on class relationships for n in exceptions: if n.__base__ in exceptions: exceptions.add_edge(n.__base__, n) sorted_exceptions = nx.topological_sort(exceptions) self.catches = [''' #ifdef PYTHONIC_BUILTIN_{uname}_HPP catch(pythonic::types::{name} & e) {{ PyErr_SetString(PyExc_{name}, pythonic::__builtin__::functor::str{{}}(e.args).c_str()); }} #endif '''.format(name=n.__name__, uname=n.__name__.upper()) for n in sorted_exceptions] self.catches.append(''' catch(...) { PyErr_SetString(PyExc_RuntimeError, "Something happened on the way to heaven" ); }''')
def generate_cxx(module_name, code, specs=None, optimizations=None): '''python + pythran spec -> c++ code returns a BoostPythonModule object ''' pm = PassManager(module_name) # front end ir, renamings = frontend.parse(pm, code) # middle-end optimizations = (optimizations or cfg.get('pythran', 'optimizations').split()) optimizations = map(_parse_optimization, optimizations) refine(pm, ir, optimizations) # back-end content = pm.dump(Cxx, ir) # instanciate the meta program if specs is None: class Generable: def __init__(self, content): self.content = content def __str__(self): return str(self.content) generate = __str__ mod = Generable(content) else: # uniform typing for fname, signatures in specs.items(): if not isinstance(signatures, tuple): specs[fname] = (signatures,) # verify the pythran export are compatible with the code specs = expand_specs(specs) check_specs(ir, specs, renamings) mod = BoostPythonModule(module_name) mod.use_private_namespace = False # very low value for max_arity leads to various bugs min_val = 2 specs_max = [max(map(len, s)) for s in specs.itervalues()] max_arity = max([min_val] + specs_max) mod.add_to_preamble([Define("BOOST_PYTHON_MAX_ARITY", max_arity)]) mod.add_to_preamble([Define("BOOST_SIMD_NO_STRICT_ALIASING", "1")]) mod.add_to_preamble([Include("pythonic/core.hpp")]) mod.add_to_preamble([Include("pythonic/python/core.hpp")]) mod.add_to_preamble([Line("#ifdef _OPENMP\n#include <omp.h>\n#endif")]) mod.add_to_preamble(map(Include, _extract_specs_dependencies(specs))) mod.add_to_preamble(content.body) mod.add_to_init([ Line('#ifdef PYTHONIC_TYPES_NDARRAY_HPP\nimport_array()\n#endif')]) # topologically sorted exceptions based on the inheritance hierarchy. # needed because otherwise boost python register_exception handlers # do not catch exception type in the right way # (first valid exception is selected) # Inheritance has to be taken into account in the registration order. exceptions = nx.DiGraph() for function_name, v in functions.iteritems(): for mname, symbol in v: if isinstance(symbol, ConstExceptionIntr): exceptions.add_node( getattr(sys.modules[".".join(mname)], function_name)) # add edges based on class relationships for n in exceptions: if n.__base__ in exceptions: exceptions.add_edge(n.__base__, n) sorted_exceptions = nx.topological_sort(exceptions) mod.add_to_init([ # register exception only if they can be raise from C++ world to # Python world. Preprocessors variables are set only if deps # analysis detect that this exception can be raised Line('#ifdef PYTHONIC_BUILTIN_%s_HPP\n' 'boost::python::register_exception_translator<' 'pythonic::types::%s>(&pythonic::translate_%s);\n' '#endif' % (n.__name__.upper(), n.__name__, n.__name__) ) for n in sorted_exceptions]) mod.add_to_init([ # make sure we get no nested parallelism that wreaks havoc in perf Line('#ifdef _OPENMP\n' 'omp_set_max_active_levels(1);\n' '#endif')]) for function_name, signatures in specs.iteritems(): internal_func_name = renamings.get(function_name, function_name) for sigid, signature in enumerate(signatures): numbered_function_name = "{0}{1}".format(internal_func_name, sigid) arguments_types = [pytype_to_ctype(t) for t in signature] has_arguments = HasArgument(internal_func_name).visit(ir) arguments = ["a{0}".format(i) for i in xrange(len(arguments_types))] name_fmt = pythran_ward + "{0}::{1}::type{2}" args_list = ", ".join(arguments_types) specialized_fname = name_fmt.format(module_name, internal_func_name, "<{0}>".format(args_list) if has_arguments else "") result_type = ("typename std::remove_cv<" "typename std::remove_reference" "<typename {0}::result_type>::type" ">::type").format(specialized_fname) mod.add_to_init( [Statement("pythonic::python_to_pythran<{0}>()".format(t)) for t in _extract_all_constructed_types(signature)]) mod.add_to_init([Statement( "pythonic::pythran_to_python<{0}>()".format(result_type))]) mod.add_function( FunctionBody( FunctionDeclaration( Value( result_type, numbered_function_name), [Value(t, a) for t, a in zip(arguments_types, arguments)]), Block([Statement("return {0}()({1})".format( pythran_ward + '{0}::{1}'.format( module_name, internal_func_name), ', '.join(arguments)))]) ), function_name ) # call __init__() to execute top-level statements init_call = '::'.join([pythran_ward + module_name, '__init__()()']) mod.add_to_init([Statement(init_call)]) return mod